增加ResponsivePanel 调整绘图API

This commit is contained in:
小红帽 2023-12-19 22:11:21 +08:00
parent fb9b04e7a0
commit 906c865964
97 changed files with 1327 additions and 16705 deletions

View File

@ -440,7 +440,7 @@ namespace CPF.Skia
InitializeBrush(strokeBrush);
paintWrapper = CreatePaint(strokeBrush, stroke, font);
}
var drawline = decoration.Stroke.Width > 0 && decoration.Brush != null;
var drawline = decoration.Stroke.Width > 0 && decoration.Brush != null && decoration.Location != TextDecorationLocation.None;
List<LinePosition> linePositions = null;
if (drawline)
{
@ -460,6 +460,8 @@ namespace CPF.Skia
if (textAlignment != TextAlignment.Left && maxWidth != float.MaxValue || drawline)
{
w = paint.Paint.MeasureString(text);
if (textAlignment != TextAlignment.Left && maxWidth != float.MaxValue)
{
if (textAlignment == TextAlignment.Right)
{
x = x + (maxWidth - w);
@ -469,6 +471,7 @@ namespace CPF.Skia
x = x + (maxWidth - w) / 2;
}
}
}
if (strokeBrush != null && stroke.Width > 0)
{
//using (var path = paintWrapper.Paint.GetTextPath(text, x, location.Y - paintWrapper.Paint.FontMetrics.Ascent))
@ -490,17 +493,17 @@ namespace CPF.Skia
{
w += 2;
}
switch (decoration.Location)
if (decoration.Location.HasFlag(TextDecorationLocation.Underline))
{
case TextDecorationLocation.Underline:
linePositions.Add(new LinePosition { X = x, Y = location.Y + paint.Paint.FontSpacing, Width = w });
break;
case TextDecorationLocation.OverLine:
}
if (decoration.Location.HasFlag(TextDecorationLocation.OverLine))
{
linePositions.Add(new LinePosition { X = x, Y = location.Y, Width = w });
break;
case TextDecorationLocation.Strikethrough:
}
if (decoration.Location.HasFlag(TextDecorationLocation.Strikethrough))
{
linePositions.Add(new LinePosition { X = x, Y = location.Y + paint.Paint.FontSpacing / 2, Width = w });
break;
}
}
}
@ -616,17 +619,17 @@ namespace CPF.Skia
}
if (drawline)
{
switch (decoration.Location)
if (decoration.Location.HasFlag(TextDecorationLocation.Underline))
{
case TextDecorationLocation.Underline:
linePositions.Add(new LinePosition { X = xx, Y = item.y + paint.Paint.FontSpacing + paint.Paint.FontMetrics.Ascent, Width = item.w });
break;
case TextDecorationLocation.OverLine:
}
if (decoration.Location.HasFlag(TextDecorationLocation.OverLine))
{
linePositions.Add(new LinePosition { X = xx, Y = item.y + paint.Paint.FontMetrics.Ascent, Width = item.w });
break;
case TextDecorationLocation.Strikethrough:
}
if (decoration.Location.HasFlag(TextDecorationLocation.Strikethrough))
{
linePositions.Add(new LinePosition { X = xx, Y = item.y + paint.Paint.FontSpacing / 2 + paint.Paint.FontMetrics.Ascent, Width = item.w });
break;
}
}
}
@ -636,10 +639,10 @@ namespace CPF.Skia
paintWrapper?.Dispose();
if (drawline)
{
using (var brush = decoration.Brush)
//using (var brush = decoration.Brush)
{
InitializeBrush(brush);
using (var paint = CreatePaint(brush, decoration.Stroke))
InitializeBrush(decoration.Brush);
using (var paint = CreatePaint(decoration.Brush, decoration.Stroke))
{
foreach (var item in linePositions)
{
@ -662,7 +665,7 @@ namespace CPF.Skia
InitializeBrush(strokeBrush);
paintWrapper = CreatePaint(strokeBrush, stroke, font);
}
var drawline = decoration.Stroke.Width > 0 && decoration.Brush != null;
var drawline = decoration.Stroke.Width > 0 && decoration.Brush != null && decoration.Location != TextDecorationLocation.None;
List<LinePosition> linePositions = null;
if (drawline)
{
@ -680,6 +683,8 @@ namespace CPF.Skia
if (textAlignment != TextAlignment.Left && maxWidth != float.MaxValue || drawline)
{
w = paint.Paint.MeasureString(text);
if (textAlignment != TextAlignment.Left && maxWidth != float.MaxValue)
{
if (textAlignment == TextAlignment.Right)
{
x = x + (maxWidth - w);
@ -689,6 +694,7 @@ namespace CPF.Skia
x = x + (maxWidth - w) / 2;
}
}
}
if (strokeBrush != null && stroke.Width > 0)
{
canvas.DrawTextPath(paint.Paint, paintWrapper.Paint, text, x, location.Y - paintWrapper.Paint.FontMetrics.Ascent);
@ -705,17 +711,17 @@ namespace CPF.Skia
{
w += 2;
}
switch (decoration.Location)
if (decoration.Location.HasFlag(TextDecorationLocation.Underline))
{
case TextDecorationLocation.Underline:
linePositions.Add(new LinePosition { X = x, Y = location.Y + paint.Paint.FontSpacing, Width = w });
break;
case TextDecorationLocation.OverLine:
}
if (decoration.Location.HasFlag(TextDecorationLocation.OverLine))
{
linePositions.Add(new LinePosition { X = x, Y = location.Y, Width = w });
break;
case TextDecorationLocation.Strikethrough:
}
if (decoration.Location.HasFlag(TextDecorationLocation.Strikethrough))
{
linePositions.Add(new LinePosition { X = x, Y = location.Y + paint.Paint.FontSpacing / 2, Width = w });
break;
}
}
}
@ -764,6 +770,8 @@ namespace CPF.Skia
if (textAlignment != TextAlignment.Left && maxWidth != float.MaxValue || drawline)
{
w = paint.Paint.MeasureString(newText);
if (textAlignment != TextAlignment.Left && maxWidth != float.MaxValue)
{
if (textAlignment == TextAlignment.Right)
{
x = x + (maxWidth - w);
@ -773,6 +781,7 @@ namespace CPF.Skia
x = x + (maxWidth - w) / 2;
}
}
}
if (strokeBrush != null && stroke.Width > 0)
{
canvas.DrawTextPath(paint.Paint, paintWrapper.Paint, newText, x, location.Y - paintWrapper.Paint.FontMetrics.Ascent);
@ -789,17 +798,17 @@ namespace CPF.Skia
{
w += 2;
}
switch (decoration.Location)
if (decoration.Location.HasFlag(TextDecorationLocation.Underline))
{
case TextDecorationLocation.Underline:
linePositions.Add(new LinePosition { X = x, Y = location.Y + paint.Paint.FontSpacing, Width = w });
break;
case TextDecorationLocation.OverLine:
}
if (decoration.Location.HasFlag(TextDecorationLocation.OverLine))
{
linePositions.Add(new LinePosition { X = x, Y = location.Y, Width = w });
break;
case TextDecorationLocation.Strikethrough:
}
if (decoration.Location.HasFlag(TextDecorationLocation.Strikethrough))
{
linePositions.Add(new LinePosition { X = x, Y = location.Y + paint.Paint.FontSpacing / 2, Width = w });
break;
}
}
}
@ -807,10 +816,10 @@ namespace CPF.Skia
paintWrapper?.Dispose();
if (drawline)
{
using (var brush = decoration.Brush)
//using (var brush = decoration.Brush)
{
InitializeBrush(brush);
using (var paint = CreatePaint(brush, decoration.Stroke))
InitializeBrush(decoration.Brush);
using (var paint = CreatePaint(decoration.Brush, decoration.Stroke))
{
foreach (var item in linePositions)
{

View File

@ -303,7 +303,7 @@ namespace CPF.Skia
}
}
public override float GetDefaultLineHeight(in Font font)
public override float GetLineHeight(in Font font)
{
using (SKPaint paint = new SKPaint())
{
@ -318,6 +318,38 @@ namespace CPF.Skia
return paint.FontSpacing;
}
}
public override float GetAscent(in Font font)
{
using (SKPaint paint = new SKPaint())
{
paint.TextEncoding = SKTextEncoding.Utf16;
//paint.IsStroke = false;
//paint.LcdRenderText = true;
//paint.SubpixelText = true;
paint.IsAntialias = true;
paint.Typeface = (font.AdapterFont as FontWrapper).SKTypeface;
paint.TextSize = font.FontSize;
return -paint.FontMetrics.Ascent;
}
}
public override float GetDescent(in Font font)
{
using (SKPaint paint = new SKPaint())
{
paint.TextEncoding = SKTextEncoding.Utf16;
//paint.IsStroke = false;
//paint.LcdRenderText = true;
//paint.SubpixelText = true;
paint.IsAntialias = true;
paint.Typeface = (font.AdapterFont as FontWrapper).SKTypeface;
paint.TextSize = font.FontSize;
return paint.FontMetrics.Descent;
}
}
}
class FontWrapper : IDisposable

View File

@ -125,5 +125,10 @@ namespace CPF.Skia
return new SkiaPath(p);
}
}
public void Reset()
{
path.Reset();
}
}
}

View File

@ -341,20 +341,13 @@ namespace CPF.GDIPlus
}
if (drawLine)
{
var ly = y;
switch (decoration.Location)
{
case TextDecorationLocation.Underline:
ly = y + fHeight;
break;
case TextDecorationLocation.OverLine:
break;
case TextDecorationLocation.Strikethrough:
ly = y + fHeight / 2;
break;
}
var lw = drawingFactory.g.MeasureString(sub, f.Font).Width;
if (decoration.Location.HasFlag(TextDecorationLocation.Underline))
{
var ly = y;
ly = y + fHeight;
var lx = x;
switch (textAlignment)
{
@ -367,6 +360,40 @@ namespace CPF.GDIPlus
}
g.DrawLine(pen, lx, ly, lx + lw, ly);
}
if (decoration.Location.HasFlag(TextDecorationLocation.OverLine))
{
var ly = y;
var lx = x;
switch (textAlignment)
{
case TextAlignment.Right:
lx = x + mw - lw;
break;
case TextAlignment.Center:
lx = x + (mw - lw) / 2;
break;
}
g.DrawLine(pen, lx, ly, lx + lw, ly);
}
if (decoration.Location.HasFlag(TextDecorationLocation.Strikethrough))
{
var ly = y;
ly = y + fHeight / 2;
var lx = x;
switch (textAlignment)
{
case TextAlignment.Right:
lx = x + mw - lw;
break;
case TextAlignment.Center:
lx = x + (mw - lw) / 2;
break;
}
g.DrawLine(pen, lx, ly, lx + lw, ly);
}
}
y += fHeight;
index += count;
@ -524,20 +551,13 @@ namespace CPF.GDIPlus
}
if (drawLine)
{
var ly = y;
switch (decoration.Location)
{
case TextDecorationLocation.Underline:
ly = y + fHeight;
break;
case TextDecorationLocation.OverLine:
break;
case TextDecorationLocation.Strikethrough:
ly = y + fHeight / 2;
break;
}
var lw = drawingFactory.g.MeasureString(sub, f.Font).Width;
if (decoration.Location.HasFlag(TextDecorationLocation.Underline))
{
var ly = y;
ly = y + fHeight;
var lx = x;
switch (textAlignment)
{
@ -550,6 +570,40 @@ namespace CPF.GDIPlus
}
g.DrawLine(pen, lx, ly, lx + lw, ly);
}
if (decoration.Location.HasFlag(TextDecorationLocation.OverLine))
{
var ly = y;
var lx = x;
switch (textAlignment)
{
case TextAlignment.Right:
lx = x + mw - lw;
break;
case TextAlignment.Center:
lx = x + (mw - lw) / 2;
break;
}
g.DrawLine(pen, lx, ly, lx + lw, ly);
}
if (decoration.Location.HasFlag(TextDecorationLocation.Strikethrough))
{
var ly = y;
ly = y + fHeight / 2;
var lx = x;
switch (textAlignment)
{
case TextAlignment.Right:
lx = x + mw - lw;
break;
case TextAlignment.Center:
lx = x + (mw - lw) / 2;
break;
}
g.DrawLine(pen, lx, ly, lx + lw, ly);
}
}
y += fHeight;
index += count;

View File

@ -232,10 +232,31 @@ namespace CPF.GDIPlus
}
}
public override float GetDefaultLineHeight(in Drawing.Font font)
public override float GetLineHeight(in Drawing.Font font)
{
//var f = (FontStruct)font.AdapterFont;
//return f.Height;
var f = (FontStruct)font.AdapterFont;
float emHeight = f.Font.FontFamily.GetEmHeight(f.Font.Style);
var lineSpacing = f.Font.FontFamily.GetLineSpacing(f.Font.Style) * f.Font.Size / emHeight;
return lineSpacing;
}
public override float GetAscent(in Drawing.Font font)
{
var f = (FontStruct)font.AdapterFont;
return f.Height;
float emHeight = f.Font.FontFamily.GetEmHeight(f.Font.Style);
//var lineSpacing = f.Font.FontFamily.GetLineSpacing(f.Font.Style) * f.Font.Size / emHeight;
float ascent = f.Font.FontFamily.GetCellAscent(f.Font.Style) * f.Font.Size / emHeight;
return ascent;
}
public override float GetDescent(in Drawing.Font font)
{
var f = (FontStruct)font.AdapterFont;
float emHeight = f.Font.FontFamily.GetEmHeight(f.Font.Style);
float descent = f.Font.FontFamily.GetCellDescent(f.Font.Style) * f.Font.Size / emHeight;
return descent;
}
///// <summary>

View File

@ -272,6 +272,11 @@ namespace CPF.GDIPlus
return new GDIPlusPath(p);
}
public void Reset()
{
path.Reset();
}
~GDIPlusPath()
{
Dispose();

View File

@ -51,19 +51,18 @@ namespace CPF.Windows.OpenGL
//Wgl.WGL_ALPHA_BITS_ARB, 8,
////Wgl.WGL_SAMPLE_BUFFERS_ARB, 1, // MSAA on,开启多重采样
////Wgl.WGL_SAMPLES_ARB, 4, // 4x MSAA ,多重采样样本数量为4
//0, 0
//}, new float[] { 0, 0 }, 1, nPixelFormat, out var f);
//Wgl.SetPixelFormat(dc, nPixelFormat[0], ref pfd);
//r= Wgl.SetPixelFormat(dc, nPixelFormat[0], ref pfd);
//rc = Wgl.WglCreateContextAttribsArb(dc, IntPtr.Zero,
//new[]
//{
// // major
// WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
// // minor
// WGL_CONTEXT_MINOR_VERSION_ARB, 0,
// WGL_CONTEXT_MINOR_VERSION_ARB, 3,
// // core profile
// WGL_CONTEXT_PROFILE_MASK_ARB, 1,
// //WGL_CONTEXT_PROFILE_MASK_ARB, 0,
// // debug
// // WGL_CONTEXT_FLAGS_ARB, 1,
// // end
@ -73,6 +72,7 @@ namespace CPF.Windows.OpenGL
if (rc == IntPtr.Zero)
{
Console.WriteLine("无法创建OpenGLContext DC:" + dc + " Handle:" + handle);
System.Diagnostics.Debug.WriteLine("无法创建OpenGLContext DC:" + dc + " Handle:" + handle);
}
else
{

View File

@ -605,7 +605,7 @@ namespace CPF.Charts
if (length > 1)
{
var count = (width + size.Width) / ((w1 + size.Width) / 2 + Font.DefaultLineHeight);
var count = (width + size.Width) / ((w1 + size.Width) / 2 + Font.LineHeight);
var offset = 1.0 * (width) / (length - 1);
var of = length / count;
if (of < 1)
@ -639,7 +639,7 @@ namespace CPF.Charts
{
g.DrawLine(new Stroke(1), gpen, new Point(x, ownerSize.Height - padding.Bottom), new Point(x, padding.Top));
}
g.DrawString(new Point(x - cs.Width / 2, ownerSize.Height - padding.Bottom + Font.DefaultLineHeight / 4), foreColorBrush, c, Font, TextAlignment.Center, cs.Width + cs.Width / 5);
g.DrawString(new Point(x - cs.Width / 2, ownerSize.Height - padding.Bottom + Font.LineHeight / 4), foreColorBrush, c, Font, TextAlignment.Center, cs.Width + cs.Width / 5);
}
w = cs.Width;
index += of;

View File

@ -682,7 +682,7 @@ namespace CPF.Controls
var size = codeTextView.ActualSize;
using (var font = new Font(FontFamily, FontSize, FontStyle))
{
var lineHeight = (float)Math.Round(font.DefaultLineHeight, 2);
var lineHeight = (float)Math.Round(font.LineHeight, 2);
var len = (int)Math.Ceiling(size.Height / lineHeight);
scrollViewer.PageDown();
@ -705,7 +705,7 @@ namespace CPF.Controls
var size = codeTextView.ActualSize;
using (var font = new Font(FontFamily, FontSize, FontStyle))
{
var lineHeight = (float)Math.Round(font.DefaultLineHeight, 2);
var lineHeight = (float)Math.Round(font.LineHeight, 2);
var len = (int)Math.Ceiling(size.Height / lineHeight);
scrollViewer.PageUp();

View File

@ -191,7 +191,7 @@ namespace CPF.Controls
using (var font = new Font(textBox.FontFamily, textBox.FontSize, textBox.FontStyle))
{
lines.Clear();
var lineHeight = (float)Math.Round(font.DefaultLineHeight, 2);
var lineHeight = (float)Math.Round(font.LineHeight, 2);
var top = 0d;//换成双精度减少误差
var h = 0d;
float left = 0;
@ -304,7 +304,7 @@ namespace CPF.Controls
VerticalOffset = 0;
}
lineLayoutWidth.Clear();
var lineHeight = (float)Math.Round(font.DefaultLineHeight, 2);
var lineHeight = (float)Math.Round(font.LineHeight, 2);
var len = Math.Ceiling(size.Height / lineHeight);
var start = (int)Math.Floor(VerticalOffset / lineHeight);
textBox.LineNumber.Start = start;
@ -380,7 +380,7 @@ namespace CPF.Controls
using (var font = new Font(textBox.FontFamily, textBox.FontSize, textBox.FontStyle))
{
HybridDictionary<int, Cache> caches = new HybridDictionary<int, Cache>();
var lineHeight = (float)Math.Round(font.DefaultLineHeight, 2);
var lineHeight = (float)Math.Round(font.LineHeight, 2);
var len = Math.Ceiling(size.Height / lineHeight);
var start = (int)Math.Floor(vo / lineHeight);
@ -634,7 +634,7 @@ namespace CPF.Controls
{
using (var font = new Font(textBox.FontFamily, textBox.FontSize, textBox.FontStyle))
{
lineHeight = (float)Math.Round(font.DefaultLineHeight, 2);
lineHeight = (float)Math.Round(font.LineHeight, 2);
var ho = HorizontalOffset;
var vo = VerticalOffset;
var start = (int)Math.Floor(vo / lineHeight);
@ -688,7 +688,7 @@ namespace CPF.Controls
//var size = new Size(ViewportWidth, ViewportHeight);
using (var font = new Font(textBox.FontFamily, textBox.FontSize, textBox.FontStyle))
{
var lineHeight = Math.Round(font.DefaultLineHeight, 2);
var lineHeight = Math.Round(font.LineHeight, 2);
var ho = (double)HorizontalOffset + point.X;
var vo = (double)VerticalOffset;
var start = (int)Math.Floor(vo / lineHeight);

View File

@ -151,6 +151,14 @@ namespace CPF.Controls
get { return GetValue<CustomScrollData>(); }
set { SetValue(value); }
}
/// <summary>
/// 获取或设置一个值,该值指示是否自动创建列
/// </summary>
public bool AutoGenerateColumns
{
get { return GetValue<bool>(); }
set { SetValue(value); }
}
protected override void InitializeComponent()
{
@ -687,13 +695,117 @@ namespace CPF.Controls
}
[PropertyChanged(nameof(Items))]
void RegisterItems(object newValue, object oldValue, PropertyMetadataAttribute attribute)
void OnItems(object newValue, object oldValue, PropertyMetadataAttribute attribute)
{
if (presenter)
{
presenter.Items = newValue as IList;
}
}
protected override bool OnSetValue(string propertyName, ref object value)
{
if (propertyName == nameof(Items) && AutoGenerateColumns)
{
Items.Clear();
Columns.Clear();
if (value != null)
{
//if (value is DataRows rows)
//{
// foreach (var item in rows.DataTable.Columns)
// {
// }
//}
if (value is IList list)
{
if (list.Count > 0)
{
var v = list[0];
if (v is CpfObject cpf)
{
foreach (var item in cpf.GetProperties())
{
CreateColumn(item.PropertyType, item.PropertyName);
}
}
else
{
var t = v.GetType();
var ps = t.GetProperties();
foreach (var item in ps)
{
CreateColumn(item.PropertyType, item.Name);
}
}
}
else if (list.Count == 0)
{
var t = list.GetType();
if (t.IsArray)
{
var ps = t.GetElementType().GetProperties();
foreach (var item in ps)
{
CreateColumn(item.PropertyType, item.Name);
}
}
else
{
var gs = t.GetGenericArguments();
if (gs != null && gs.Length == 1)
{
var ps = gs[0].GetProperties();
foreach (var item in ps)
{
CreateColumn(item.PropertyType, item.Name);
}
}
}
}
}
}
}
return base.OnSetValue(propertyName, ref value);
}
private void CreateColumn(Type PropertyType, string PropertyName)
{
DataGridColumn column;
if (PropertyType == typeof(bool))
{
column = new DataGridCheckBoxColumn { };
}
else if (PropertyType.IsEnum)
{
//var kp = new List<(string, object)>();
//var vs = Enum.GetValues(item.PropertyType);
//foreach (var vv in vs)
//{
// kp.Add((Enum.GetName(item.PropertyType, vv), vv));
//}
//column = new DataGridComboBoxColumn { DisplayMemberPath = "Item1", SelectedValuePath = "Item2", Items = kp };
column = new DataGridComboBoxColumn { Items = Enum.GetValues(PropertyType) };
}
else
{
column = new DataGridTextColumn { };
}
column.Width = 100;
column.Binding = PropertyName;
column.Header = PropertyName;
var auto = new DataGridAutoGeneratingColumnEventArgs(column, PropertyName, PropertyType);
OnAutoGeneratingColumn(auto);
if (!auto.Cancel && auto.Column != null)
{
Columns.Add(auto.Column);
}
}
//protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
//{
// if (propertyName == nameof(Items) && presenter)
@ -1067,6 +1179,17 @@ namespace CPF.Controls
overridePropertys.Override(nameof(ItemTemplate), new PropertyMetadataAttribute((UIElementTemplate<DataGridRow>)typeof(DataGridRow)));
}
public event EventHandler<DataGridAutoGeneratingColumnEventArgs> AutoGeneratingColumn
{
add { AddHandler(value); }
remove { RemoveHandler(value); }
}
protected virtual void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs eventArgs)
{
this.RaiseEvent(eventArgs, nameof(AutoGeneratingColumn));
}
class EditCell
{
public int RowIndex;
@ -1146,4 +1269,20 @@ namespace CPF.Controls
/// </summary>
public DataGridCellTemplate EditingElement { get; private set; }
}
public class DataGridAutoGeneratingColumnEventArgs : EventArgs
{
public DataGridAutoGeneratingColumnEventArgs(DataGridColumn column, string propertyName, Type propertyType)
{
Column = column;
PropertyName = propertyName;
PropertyType = propertyType;
}
public bool Cancel { get; set; }
public DataGridColumn Column { get; set; }
public string PropertyName { get; }
public Type PropertyType { get; }
}
}

View File

@ -0,0 +1,719 @@
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CPF.Controls
{
/// <summary>
/// 响应式布局容器模仿bootstrap
/// XS(&lt;768px), SM(&lt;992px), MD(&lt;1200px), LG(1200px&gt;=)
/// 整个页面有12列。(可使用MaxDivision、BreakPoints属性自定义)
/// </summary>
[Description("响应式布局容器模仿bootstrap")]
public class ResponsivePanel : Panel
{
/// <summary>
/// 响应式布局容器模仿bootstrap
/// XS(&lt;768px), SM(&lt;992px), MD(&lt;1200px), LG(1200px&gt;=)
/// 整个页面有12列。(可使用MaxDivision、BreakPoints属性自定义)
/// </summary>
public ResponsivePanel()
{
}
/// <summary>
/// 定义列数
/// </summary>
[Description("定义列数")]
[UIPropertyMetadata(12, UIPropertyOptions.AffectsMeasure)]
public int MaxDivision
{
get { return (int)GetValue(); }
set { SetValue(value); }
}
/// <summary>
/// 定义响应布局的尺寸
/// </summary>
[Description("定义响应布局的尺寸")]
public BreakPoints BreakPoints
{
get { return (BreakPoints)GetValue(); }
set { SetValue(value); }
}
/// <summary>
/// 显示分割列线条
/// </summary>
[Description("显示分割列线条")]
public bool ShowGridLines
{
get { return (bool)GetValue(); }
set { SetValue(value); }
}
/// <summary>
/// 尺寸状态 XS, SM, MD, LG
/// </summary>
[Description("尺寸状态 XS, SM, MD, LG")]
public ResponsiveState State
{
get { return (ResponsiveState)GetValue(); }
private set { SetValue(value); }
}
public static Attached<int> XS
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> SM
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> MD
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> LG
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> XS_Offset
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> SM_Offset
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> MD_Offset
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> LG_Offset
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> XS_Push
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> SM_Push
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> MD_Push
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> LG_Push
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> XS_Pull
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> SM_Pull
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> MD_Pull
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
public static Attached<int> LG_Pull
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
[Browsable(false)]
public static Attached<int> ActualColumn
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel));
}
}
[Browsable(false)]
public static Attached<int> ActualRow
{
get
{
return RegisterAttached(0, typeof(ResponsivePanel));
}
}
public static Attached<RVisible> Visible
{
get
{
return RegisterAttached(RVisible.Visible, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
{
if (obj is UIElement element && element.Parent != null)
{
element.Parent.InvalidateMeasure();
}
});
}
}
//public static Attached<RHidden> Hidden
//{
// get
// {
// return RegisterAttached(RHidden.None, typeof(ResponsivePanel), (CpfObject obj, string propertyName, object defaultValue, object oldValue, ref object newValue) =>
// {
// if (obj is UIElement element && element.Parent != null)
// {
// element.Parent.InvalidateMeasure();
// }
// });
// }
//}
protected int GetSpan(in BreakPoints breakPoints, UIElement element, double width)
{
var span = 0;
var getXS = new Func<UIElement, int>((o) => { var x = XS(o); return x != 0 ? x : this.MaxDivision; });
var getSM = new Func<UIElement, int>((o) => { var x = SM(o); return x != 0 ? x : getXS(o); });
var getMD = new Func<UIElement, int>((o) => { var x = MD(o); return x != 0 ? x : getSM(o); });
var getLG = new Func<UIElement, int>((o) => { var x = LG(o); return x != 0 ? x : getMD(o); });
if (width < breakPoints.XS_SM)
{
span = getXS(element);
}
else if (width < breakPoints.SM_MD)
{
span = getSM(element);
}
else if (width < breakPoints.MD_LG)
{
span = getMD(element);
}
else
{
span = getLG(element);
}
return Math.Min(Math.Max(0, span), this.MaxDivision); ;
}
protected int GetOffset(in BreakPoints breakPoints, UIElement element, double width)
{
var span = 0;
var getXS = new Func<UIElement, int>((o) => { var x = XS_Offset(o); return x != 0 ? x : 0; });
var getSM = new Func<UIElement, int>((o) => { var x = SM_Offset(o); return x != 0 ? x : getXS(o); });
var getMD = new Func<UIElement, int>((o) => { var x = MD_Offset(o); return x != 0 ? x : getSM(o); });
var getLG = new Func<UIElement, int>((o) => { var x = LG_Offset(o); return x != 0 ? x : getMD(o); });
if (width < breakPoints.XS_SM)
{
span = getXS(element);
}
else if (width < breakPoints.SM_MD)
{
span = getSM(element);
}
else if (width < breakPoints.MD_LG)
{
span = getMD(element);
}
else
{
span = getLG(element);
}
return Math.Min(Math.Max(0, span), this.MaxDivision); ;
}
protected int GetPush(in BreakPoints breakPoints, UIElement element, double width)
{
var span = 0;
var getXS = new Func<UIElement, int>((o) => { var x = XS_Push(o); return x != 0 ? x : 0; });
var getSM = new Func<UIElement, int>((o) => { var x = SM_Push(o); return x != 0 ? x : getXS(o); });
var getMD = new Func<UIElement, int>((o) => { var x = MD_Push(o); return x != 0 ? x : getSM(o); });
var getLG = new Func<UIElement, int>((o) => { var x = LG_Push(o); return x != 0 ? x : getMD(o); });
if (width < breakPoints.XS_SM)
{
span = getXS(element);
}
else if (width < breakPoints.SM_MD)
{
span = getSM(element);
}
else if (width < breakPoints.MD_LG)
{
span = getMD(element);
}
else
{
span = getLG(element);
}
return Math.Min(Math.Max(0, span), this.MaxDivision); ;
}
protected int GetPull(in BreakPoints breakPoints, UIElement element, double width)
{
var span = 0;
var getXS = new Func<UIElement, int>((o) => { var x = XS_Pull(o); return x != 0 ? x : 0; });
var getSM = new Func<UIElement, int>((o) => { var x = SM_Pull(o); return x != 0 ? x : getXS(o); });
var getMD = new Func<UIElement, int>((o) => { var x = MD_Pull(o); return x != 0 ? x : getSM(o); });
var getLG = new Func<UIElement, int>((o) => { var x = LG_Pull(o); return x != 0 ? x : getMD(o); });
if (width < breakPoints.XS_SM)
{
span = getXS(element);
}
else if (width < breakPoints.SM_MD)
{
span = getSM(element);
}
else if (width < breakPoints.MD_LG)
{
span = getMD(element);
}
else
{
span = getLG(element);
}
return Math.Min(Math.Max(0, span), this.MaxDivision); ;
}
Visibility GetVisibility(in BreakPoints breakPoints, UIElement element, float width)
{
Visibility visibility = Visibility.Collapsed;
var v = Visible(element);
if (width < breakPoints.XS_SM && v.HasFlag(RVisible.XS))
{
visibility = Visibility.Visible;
}
else if (width >= breakPoints.XS_SM && width < breakPoints.SM_MD && v.HasFlag(RVisible.SM))
{
visibility = Visibility.Visible;
}
else if (width >= breakPoints.SM_MD && width < breakPoints.MD_LG && v.HasFlag(RVisible.MD))
{
visibility = Visibility.Visible;
}
else if (width >= breakPoints.MD_LG && v.HasFlag(RVisible.LG))
{
visibility = Visibility.Visible;
}
return visibility;
}
float availableWidth;
protected override Size MeasureOverride(in Size availableSize)
{
var count = 0;
var currentRow = 0;
availableWidth = float.IsPositiveInfinity(availableSize.Width) ? float.PositiveInfinity : availableSize.Width / this.MaxDivision;
var breakPoints = BreakPoints;
foreach (UIElement child in this.Children)
{
if (child != null)
{
var v = GetVisibility(breakPoints, child, availableSize.Width);
//child.Visibility = v;
if (v == Visibility.Collapsed) { continue; }
var span = this.GetSpan(breakPoints, child, availableSize.Width);
var offset = this.GetOffset(breakPoints, child, availableSize.Width);
var push = this.GetPush(breakPoints, child, availableSize.Width);
var pull = this.GetPull(breakPoints, child, availableSize.Width);
if (count + span + offset > this.MaxDivision)
{
currentRow++;
count = 0;
}
ActualColumn(child, count + offset + push - pull);
ActualRow(child, currentRow);
count += (span + offset);
var size = new Size(availableWidth * span, float.PositiveInfinity);
child.Measure(size);
}
}
var group = this.Children.GroupBy(x => ActualRow(x));
var totalSize = new Size();
if (group.Count() != 0)
{
totalSize.Width = group.Max(rows => rows.Sum(o => o.DesiredSize.Width));
totalSize.Height = group.Sum(rows => rows.Max(o => o.DesiredSize.Height));
}
return totalSize;
}
protected override Size ArrangeOverride(in Size finalSize)
{
var breakPoints = BreakPoints;
if (finalSize.Width != availableWidth)
{//对于测量时给的尺寸不一致时候需要重新测量一遍
var count = 0;
var currentRow = 0;
foreach (UIElement child in this.Children)
{
var v = GetVisibility(breakPoints, child, finalSize.Width);
child.Visibility = v;
if (v == Visibility.Collapsed) { continue; }
var span = this.GetSpan(breakPoints, child, finalSize.Width);
var offset = this.GetOffset(breakPoints, child, finalSize.Width);
var push = this.GetPush(breakPoints, child, finalSize.Width);
var pull = this.GetPull(breakPoints, child, finalSize.Width);
if (count + span + offset > this.MaxDivision)
{
currentRow++;
count = 0;
}
ActualColumn(child, count + offset + push - pull);
ActualRow(child, currentRow);
count += (span + offset);
}
}
var columnWidth = finalSize.Width / this.MaxDivision;
var group = this.Children.GroupBy(x => ActualRow(x));
float temp = 0;
foreach (var rows in group)
{
float max = 0;
var columnHeight = rows.Max(o => o.DesiredSize.Height);
foreach (var element in rows)
{
var column = ActualColumn(element);
var row = ActualRow(element);
var columnSpan = this.GetSpan(breakPoints, element, finalSize.Width);
var rect = new Rect(columnWidth * column, temp, columnWidth * columnSpan, columnHeight);
element.Arrange(rect);
max = Math.Max(element.DesiredSize.Height, max);
}
temp += max;
}
if (finalSize.Width < breakPoints.XS_SM)
{
State = ResponsiveState.XS;
}
else if (finalSize.Width >= breakPoints.XS_SM && finalSize.Width < breakPoints.SM_MD)
{
State = ResponsiveState.SM;
}
else if (finalSize.Width >= breakPoints.SM_MD && finalSize.Width < breakPoints.MD_LG)
{
State = ResponsiveState.MD;
}
else if (finalSize.Width >= breakPoints.MD_LG)
{
State = ResponsiveState.LG;
}
return finalSize;
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
if (this.ShowGridLines)
{
using (var brush = new SolidColorBrush("Yellow"))
{
using (var brush1 = new SolidColorBrush("Blue"))
{
var ds = new Stroke(1, DashStyles.Custom, 0, new float[] { 4, 4 }, CapStyles.Round);
var ds1 = new Stroke(1);
var size = ActualSize;
var gridNum = this.MaxDivision;
var unit = size.Width / gridNum;
for (var i = 0; i <= gridNum; i++)
{
var x = (int)(unit * i);
dc.DrawLine(ds1, brush, new Point(x, 0), new Point(x, size.Height));
dc.DrawLine(ds, brush1, new Point(x, 0), new Point(x, size.Height));
}
}
}
}
}
protected override void OnOverrideMetadata(OverrideMetadata overridePropertys)
{
base.OnOverrideMetadata(overridePropertys);
overridePropertys.Override(nameof(BreakPoints), new UIPropertyMetadataAttribute(BreakPoints.Default, UIPropertyOptions.AffectsMeasure));
}
}
/// <summary>
/// 定义响应布局的尺寸
/// </summary>
public struct BreakPoints
{
public float XS_SM { get; set; }
public float SM_MD { get; set; }
public float MD_LG { get; set; }
public static BreakPoints Default
{
get { return new BreakPoints { XS_SM = 768f, SM_MD = 992f, MD_LG = 1200 }; }
}
public override string ToString()
{
return $"XS_SM = {XS_SM}, SM_MD = {SM_MD}, MD_LG = {MD_LG}";
}
public static implicit operator BreakPoints(string str)
{
try
{
var t = str.Split(',');
var bp = new BreakPoints();
bp.XS_SM = float.Parse(t[0].Split('=')[1]);
bp.SM_MD = float.Parse(t[1].Split('=')[1]);
bp.MD_LG = float.Parse(t[2].Split('=')[1]);
return bp;
}
catch (Exception e)
{
throw new Exception("BreakPoints字符串格式不对", e);
}
}
}
/// <summary>
/// 响应布局元素的可见性
/// </summary>
public enum RVisible : byte
{
Hidden = 0,
XS = 1,
SM = 2,
MD = 4,
LG = 8,
Hidden_XS = SM | MD | LG,
Hidden_SM = XS | MD | LG,
Hidden_MD = XS | SM | LG,
Hidden_LG = XS | SM | MD,
Visible = XS | SM | MD | LG,
}
public enum ResponsiveState
{
XS,
SM,
MD,
LG,
}
//public enum RHidden : byte
//{
// None = 0,
// XS = 1,
// SM = 2,
// MD = 4,
// LG = 8
//}
}

View File

@ -1,75 +0,0 @@
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Text;
namespace CPF.Drawing
{
public class Graphics
{
DrawingContext drawingContext;
public Graphics(DrawingContext dc) {
drawingContext = dc;
}
public void FillRectangle(Brush brush,float x,float y, float width,float height) {
drawingContext.FillRectangle(brush, new Rect(x,y,width,height));
}
public void DrawLine(Brush brush,float x,float y,float x1,float y1,int stroke = 1)
{
drawingContext.DrawLine(new Stroke(stroke), brush,new Point(x,y),new Point(x1,y1));
}
public void DrawRectangle(Brush brush,Rect rect)
{
drawingContext.DrawRectangle(brush, new Stroke(1), rect);
}
public void DrawPath(Brush brush,PathGeometry path)
{
drawingContext.DrawPath(brush,new Stroke(1), path);
}
public void FillPath(Brush brush, PathGeometry path)
{
drawingContext.FillPath(brush, path);
}
public void FillRectangle(Brush brush,Rect rect)
{
drawingContext.FillRectangle(brush, rect);
}
public void FillRectangle(Brush brush,float x,float y,int width,int height)
{
drawingContext.FillRectangle(brush,new Rect(x,y,width,height));
}
public void DrawString(string str,Font font, Brush brush,float x, float y, StringFormat stringFormat)
{
drawingContext.DrawString(new Point(x,y),brush,str,font, stringFormat.Alignment);
}
public void DrawString(string str, Font font, Brush brush, float x, float y)
{
drawingContext.DrawString(new Point(x, y), brush, str, font);
}
public void DrawString(string str, Font font, Brush brush, Rect rect, StringFormat stringFormat)
{
drawingContext.DrawString(new Point(rect.X, rect.Y), brush, str, font,stringFormat.Alignment, rect.Width,
default,rect.Height);
}
public static Graphics FromImage(Bitmap bmp)
{
return new Graphics(DrawingContext.FromBitmap(bmp));
}
public Size MeasureString(string strText, Font ft, int v, StringFormat m_sf)
{
return Platform.Application.GetDrawingFactory().MeasureString(strText, ft,v);
}
public void DrawImage(Image image, Rect rect)
{
drawingContext.DrawImage(image, rect, rect);
}
internal void SetClip(Rect rect)
{
}
}
}

View File

@ -1,222 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ST.Library.UI.STTextBox;
using ST.Library.Drawing.SvgRender;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using CPF.Drawing;
namespace ST.Library.Drawing
{
public class EmojiRender : IEmojiRender, IDisposable
{
private Dictionary<string, string> m_dic_xml = new Dictionary<string, string>();
private Dictionary<string, CacheInfo> m_dic_cache = new Dictionary<string, CacheInfo>();
private struct CacheInfo
{
public int Size;
public Image Image;
public Image SelectedImage;
}
//private ImageAttributes m_img_attr_normal;
//private ImageAttributes m_img_attr_selected;
public EmojiRender(string strFile) {
/*ColorMatrix m = new ColorMatrix(new float[][]{
new float[]{1, 0, 0, 0, 0},
new float[]{0, 1, 0, 0, 0},
new float[]{0, 0, 1, 0, 0},
new float[]{0, 0, 0, 1, 0},
new float[]{0, 0, 0, 0, 1},
});
m_img_attr_normal = new ImageAttributes();
m_img_attr_normal.SetColorMatrix(m);
m[3, 3] = 0.5F;
m_img_attr_selected = new ImageAttributes();
m_img_attr_selected.SetColorMatrix(m);*/
this.InitSvgFromPackage(strFile);
}
public bool IsEmoji(string strChar) {
return this.GetEmojiString(strChar) != null;
}
private string GetEmojiString(string strText) {
if (m_dic_xml.ContainsKey(strText)) {
return strText;
}
// http://www.unicode.org/charts/PDF/UFE00.pdf
// FE00 - FE0F is the Variation Selectors
// FE0E -> text variation selector
// FE0F -> emoji variation selector
if (strText.IndexOf('\uFE0F') == -1) {
return null;
}
strText = strText.Replace("\uFE0F", "");// strText.Substring(0, strText.Length - 1);
if (m_dic_xml.ContainsKey(strText)) {
return strText;
}
return null;
}
public void DrawEmoji(ISTTextBoxRender render, string strChar, int nX, int nY, int nWidth, bool bSelected) {
strChar = this.GetEmojiString(strChar);
CacheInfo ci;
if (string.IsNullOrEmpty(strChar)) {
strChar = "none";
}
if (m_dic_cache.ContainsKey(strChar)) {
ci = m_dic_cache[strChar];
if (ci.Size != nWidth) {
ci.Image.Dispose();
ci.Image = this.GetEmojiImage(strChar, nWidth);
m_dic_cache[strChar] = ci;
}
} else {
ci.Size = nWidth;
ci.Image = this.GetEmojiImage(strChar, nWidth);
ci.SelectedImage = this.SetAlpha((Bitmap)ci.Image.Clone());
m_dic_cache.Add(strChar, ci);
}
Rect rect = new Rect(nX, nY, nWidth, nWidth);
render.DrawImage(bSelected ? ci.SelectedImage : ci.Image, rect);
//if (!bSelected) {
// render.DrawImage(ci.Image, rect);
//} else {
// using (Bitmap bmp = (Bitmap)ci.Image.Clone()) {
// var bmpData = bmp.LockBits(new Rectangle(0, 0, nWidth, nWidth), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
// byte[] byClr = new byte[bmpData.Stride * bmpData.Height];
// Marshal.Copy(bmpData.Scan0, byClr, 0, byClr.Length);
// for (int x = 0; x < bmp.Width; x++) {
// for (int y = 0; y < bmp.Height; y++) {
// int nIndex = y * bmpData.Stride + x * 4 + 3;
// byClr[nIndex] = (byte)(byClr[nIndex] >> 1);
// }
// }
// Marshal.Copy(byClr, 0, bmpData.Scan0, byClr.Length);
// bmp.UnlockBits(bmpData);
// render.DrawImage(bmp, rect);
// }
//}
}
public Image GetEmojiImage(string strChar, int nSize) {
strChar = this.GetEmojiString(strChar);
if (strChar == null) {
return null;
}
Bitmap bmp = new Bitmap(nSize, nSize);
Graphics g = Graphics.FromImage(bmp);
using (SvgDocument svg = SvgDocument.FromXml(m_dic_xml[strChar]))
{
svg.Draw(g, new Rect(0, 0, nSize, nSize));
}
return bmp;
}
public Image SetAlpha(Bitmap bmp) {
//确定图像的宽和高
int height = bmp.Height;
int width = bmp.Width;
using (var l = bmp.Lock())
{//l.DataPointer就是数据指针一般不建议直接使用因为不同平台不同图形适配器不同位图格式数据格式不一样那你就需要判断不同格式来遍历指针数据处理了
for (int x = 0; x < width ; x++)
{
for (int y = 0; y < height; y++)
{
l.GetPixel(x, y, out byte a, out byte r, out byte g, out byte b);
var p = (byte)Math.Min(255, 0.7 * r + (0.2 * g) + (0.1 * b));
l.SetPixel(x, y, (byte)(a >> 1), r, g, b);
} // x
} // y
}
return bmp;
}
private int InitSvgFromPackage(string strFile) {
int nCounter = 0;
Dictionary<string, string> dic = new Dictionary<string, string>();
using (StreamReader reader = new StreamReader(strFile, Encoding.UTF8)) {
string strLine = string.Empty;
while ((strLine = reader.ReadLine()) != null) {
int nIndex = strLine.IndexOf(',');
string strXml = strLine.Substring(nIndex + 1);
dic.Add(this.GetString(strLine.Substring(0, nIndex)), strXml);
}
}
if (!dic.ContainsKey("none")) {
dic.Add("none", "<svg viewBox='0,0,20,20'><rect stroke='red' fill='yellow' x='4' y='2' width='12' height='16'/><path stroke='red' fill='none' d='M8,8 v-2 h4 v4 h-2 v2'/><line stroke='red' x1='8' y1='14' x2='12' y2='14'/></svg>");
}
m_dic_xml = dic;
return nCounter;
}
public string GetString(string strText) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strText.Length; i += 4) {
sb.Append((char)(Convert.ToInt32(strText.Substring(i, 4), 16)));
}
return sb.ToString();
}
/// <summary>
/// Package all svg files to one file
/// </summary>
/// <param name="strSvgFilesPath">The svg path</param>
/// <param name="strFileOut">The out file</param>
/// <returns>Svg count</returns>
public static int PackageSvgFiles(string strSvgFilesPath, string strFileOut) {
int nCounter = 0;
Regex reg_start = new Regex(@"^\s+|\s+$", RegexOptions.Multiline);
using (StreamWriter writer = new StreamWriter(strFileOut, false, Encoding.UTF8)) {
foreach (var v in Directory.GetFiles(strSvgFilesPath, "*.svg")) {
string strName = Path.GetFileNameWithoutExtension(v);
string strText = EmojiRender.FileNameToUnicode(strName);
string strXml = File.ReadAllText(v).Trim();
strXml = reg_start.Replace(strXml, "").Replace("\r", "").Replace("\n", "");
writer.WriteLine(strText + "," + strXml);
nCounter++;
}
}
return nCounter;
}
private static string FileNameToUnicode(string strName) {
//((strText[nIndex] & 0x03FF) << 10) + (strText[nIndex + 1] & 0x03FF) + 0x10000;
strName.ToLower();
if (strName[0] == 'u') {
strName = strName.Substring(1);
}
string strRet = string.Empty;
foreach (var v in strName.Split('-', '_')) {
int number = Convert.ToInt32(v, 16);
if (number < 0x10000) {
strRet += number.ToString("X4");
} else {
number &= 0xFFFF;
int nH = (number >> 10) | 0xD800; //D800-DBFF -> hight
int nL = (number & 0x03FF) | 0xDC00; //DC00-DEFF -> low
strRet += nH.ToString("X4");
strRet += nL.ToString("X4");
}
}
return strRet;
}
public void Dispose() {
/*if (m_img_attr_normal != null) {
m_img_attr_normal.Dispose();
}
if (m_img_attr_selected != null) {
m_img_attr_selected.Dispose();
}*/
}
}
}

View File

@ -1,120 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Drawing.Drawing2D;
namespace ST.Library.Drawing.SvgRender
{
public partial class SvgAttributes : IEnumerable
{
private Dictionary<string, string> m_dic_attr_has_set = new Dictionary<string, string>();
private Dictionary<string, string> m_dic_attr_default = new Dictionary<string, string>();
public string this[string strKey] {
get {
if (m_dic_attr_has_set.ContainsKey(strKey)) {
return m_dic_attr_has_set[strKey];
}
return null;
}
}
public bool Set(string strKey, string strValue) {
if (m_dic_attr_has_set.ContainsKey(strKey)) {
if (string.IsNullOrEmpty(strValue)) {
m_dic_attr_has_set.Remove(strValue);
} else {
if (m_dic_value_check.ContainsKey(strKey)) {
if (!m_dic_value_check[strKey](strValue)) {
return false;
}
}
m_dic_attr_has_set[strKey] = strValue;
}
} else {
if (m_dic_value_check.ContainsKey(strKey)) {
if (!m_dic_value_check[strKey](strValue)) {
return false;
}
}
m_dic_attr_has_set.Add(strKey, strValue);
}
return true;
}
public bool SetDefault(string strKey, string strValue) {
if (m_dic_attr_default.ContainsKey(strKey)) {
if (string.IsNullOrEmpty(strValue)) {
m_dic_attr_default.Remove(strValue);
} else {
if (m_dic_value_check.ContainsKey(strKey)) {
if (!m_dic_value_check[strKey](strValue)) {
return false;
}
}
m_dic_attr_default[strKey] = strValue;
}
} else {
if (m_dic_value_check.ContainsKey(strKey)) {
if (!m_dic_value_check[strKey](strValue)) {
return false;
}
}
m_dic_attr_default.Add(strKey, strValue);
}
return true;
}
public string Get(string strKey) {
string str = this[strKey];
if (str != null) {
return str;
}
return this.GetDefault(strKey);
}
public string GetDefault(string strKey) {
if (m_dic_attr_default.ContainsKey(strKey)) {
return m_dic_attr_default[strKey];
}
return SvgAttributes.GetStaticDefault(strKey);
}
public static bool SetCheckCallBack(string strName, SvgAttributeValueCheckCallBack cb) {
return SvgAttributes.AddCheckCallBack(strName, cb, true);
}
public static bool AddCheckCallBack(string strName, SvgAttributeValueCheckCallBack cb, bool isOverrid) {
if (!m_dic_value_check.ContainsKey(strName)) {
m_dic_value_check.Add(strName, cb);
return true;
}
if (isOverrid) {
m_dic_value_check[strName] = cb;
return true;
}
return false;
}
public string[] GetHasSetKeys() {
return m_dic_attr_has_set.Keys.ToArray();
}
// [interface] ========================================================
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() {
foreach (var v in m_dic_attr_has_set) {
yield return v;
}
//foreach (var v in m_dic_attr_inherit) {
// yield return v;
//}
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
}
}

View File

@ -1,268 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
using CPF.Drawing;
using RectangleF = CPF.Drawing.Rect;
namespace ST.Library.Drawing.SvgRender
{
public partial class SvgDocument : SvgElement
{
public override string TargetName {
get { return "svg"; }
}
public override bool AllowElementDraw {
get { return true; }
}
public float Width { get; private set; }
public float Height { get; private set; }
public RectangleF ViewBox { get; private set; }
public float XScale { get; private set; }
public float YScale { get; private set; }
private struct DrawingRectInfo
{
public RectangleF Rect;
public float XScale;
public float YScale;
}
protected internal override void OnInitAttribute(string strName, string strValue) {
var ms = m_reg_number.Matches(strValue);
switch (strName) {
case "viewBox":
if (ms.Count == 4) {
this.ViewBox = new RectangleF(_F(ms[0].Value), _F(ms[1].Value), _F(ms[2].Value), _F(ms[3].Value));
}
break;
case "height":
if (ms.Count == 1) {
this.Height = _F(ms[0].Value);
}
break;
case "width":
if (ms.Count == 1) {
this.Width = _F(ms[0].Value);
}
break;
}
}
protected override void OnInitElementCompleted() {
if (this.ViewBox == RectangleF.Empty) {
this.ViewBox = new RectangleF(0, 0, this.Width, this.Height);
}
if (this.ViewBox.Width == 0 || this.ViewBox.Height == 0) {
return;
}
if (this.Width == 0 && this.Height == 0) {
this.Width = this.ViewBox.Width;
this.Height = this.ViewBox.Height;
} else {
if (this.Width != 0 && this.Height == 0) {
this.Height = this.ViewBox.Height * this.Width / this.ViewBox.Width;
}
if (this.Height != 0 && this.Width == 0) {
this.Width = this.ViewBox.Width * this.Height / this.ViewBox.Height;
}
}
}
public override GraphicsPath GetPath() { return null; }
public void Draw(Graphics g, Rect rectF) {
if (rectF.Width <= 0 || rectF.Height <= 0) {
return;
}
var old_g = g.Save();
g.SmoothingMode = SmoothingMode.HighQuality;
string strPreserveAspectRatio = this.Attributes["preserveAspectRatio"];
if (string.IsNullOrEmpty(strPreserveAspectRatio)) {
strPreserveAspectRatio = "xMidYMid meet";
}
var dri = this.CheckDrawingRect(rectF, strPreserveAspectRatio);
this.XScale = dri.XScale;
this.YScale = dri.YScale;
g.SetClip(rectF);
g.TranslateTransform(dri.Rect.X - this.ViewBox.X * dri.XScale, dri.Rect.Y - this.ViewBox.Y * dri.YScale);
g.ScaleTransform(dri.XScale, dri.YScale);
foreach (var v in this.Elements) {
if (v.AllowElementDraw) {
v.DrawElement(g);
}
}
g.Restore(old_g);
this.Dispose(this);
}
private void Dispose(SvgElement ele) {
foreach (SvgElement e in ele.Elements) {
this.Dispose(e);
}
ele.Dispose();
}
private DrawingRectInfo CheckDrawingRect(RectangleF rectF, string strPreserveAspectRatio) {
DrawingRectInfo dri = new DrawingRectInfo();
if (this.ViewBox.Width == 0 || this.ViewBox.Height == 0) {
dri.Rect = rectF;
dri.XScale = dri.YScale;
return dri;
}
string[] strs = Regex.Split(strPreserveAspectRatio, @"[,\s]+");
foreach (var v in strs) {
switch (v) {
case "meet":
dri = this.ProcessMeet(rectF);
break;
case "slice":
dri = this.ProcessSlice(rectF);
break;
}
}
foreach (var v in strs) {
switch (v) {
case "xMinYMin":
dri.Rect.Location = this.ProcessXMinYMin(rectF, dri.Rect);
break;
case "xMidYMin":
dri.Rect.Location = this.ProcessXMidYMin(rectF, dri.Rect);
break;
case "xMaxYMin":
dri.Rect.Location = this.ProcessXMaxYMin(rectF, dri.Rect);
break;
case "xMinYMid":
dri.Rect.Location = this.ProcessXMinYMid(rectF, dri.Rect);
break;
case "xMidYMid":
dri.Rect.Location = this.ProcessXMidYMid(rectF, dri.Rect);
break;
case "xMaxYMid":
dri.Rect.Location = this.ProcessXMaxYMid(rectF, dri.Rect);
break;
case "xMinYMax":
dri.Rect.Location = this.ProcessXMinYMax(rectF, dri.Rect);
break;
case "xMidYMax":
dri.Rect.Location = this.ProcessXMidYMax(rectF, dri.Rect);
break;
case "xMaxYMax":
dri.Rect.Location = this.ProcessXMaxYMax(rectF, dri.Rect);
break;
}
}
return dri;
}
private DrawingRectInfo ProcessMeet(RectangleF rectF) {
var dri = new DrawingRectInfo();
float temp = this.ViewBox.Width / this.ViewBox.Height;
if (rectF.Width / rectF.Height > temp) {
dri.YScale = dri.XScale = rectF.Height / this.ViewBox.Height;
dri.Rect.Width = this.ViewBox.Width * dri.XScale;
dri.Rect.Height = rectF.Height;
dri.Rect.Y = rectF.Y;
dri.Rect.X = rectF.X + (rectF.Width - dri.Rect.Width) / 2;
} else {
dri.YScale = dri.XScale = rectF.Width / this.ViewBox.Width;
dri.Rect.Height = this.ViewBox.Height * dri.YScale;
dri.Rect.Width = rectF.Width;
dri.Rect.X = rectF.X;
dri.Rect.Y = rectF.Y + (rectF.Height - dri.Rect.Height) / 2;
}
return dri;
}
private DrawingRectInfo ProcessSlice(RectangleF rectF) {
var dri = new DrawingRectInfo();
float temp = this.ViewBox.Width / this.ViewBox.Height;
if (rectF.Width / rectF.Height > temp) {
dri.YScale = dri.XScale = rectF.Width / this.ViewBox.Width;
dri.Rect.Height = this.ViewBox.Height * dri.YScale;
dri.Rect.Width = rectF.Width;
dri.Rect.X = rectF.X;
dri.Rect.Y = rectF.Y + (rectF.Height - dri.Rect.Height) / 2;
} else {
dri.YScale = dri.XScale = rectF.Height / this.ViewBox.Height;
dri.Rect.Width = this.ViewBox.Width * dri.XScale;
dri.Rect.Height = rectF.Height;
dri.Rect.Y = rectF.Y;
dri.Rect.X = rectF.X + (rectF.Width - dri.Rect.Width) / 2;
}
return dri;
}
private PointF ProcessXMinYMin(RectangleF rectF, RectangleF rectFView) {
return rectF.Location;
}
private PointF ProcessXMidYMin(RectangleF rectF, RectangleF rectFView) {
rectF.X += (rectF.Width - rectFView.Width) / 2;
return rectF.Location;
}
private PointF ProcessXMaxYMin(RectangleF rectF, RectangleF rectFView) {
rectF.X = rectF.Right - rectFView.Width;
return rectF.Location;
}
private PointF ProcessXMinYMid(RectangleF rectF, RectangleF rectFView) {
rectF.Y = rectF.Y + (rectF.Height - rectFView.Height) / 2;
return rectF.Location;
}
private PointF ProcessXMidYMid(RectangleF rectF, RectangleF rectFView) {
rectF.X = rectF.X + (rectF.Width - rectFView.Width) / 2;
rectF.Y = rectF.Y + (rectF.Height - rectFView.Height) / 2;
return rectF.Location;
}
private PointF ProcessXMaxYMid(RectangleF rectF, RectangleF rectFView) {
rectF.X = rectF.Right - rectFView.Width;
rectF.Y = rectF.Y + (rectF.Height - rectFView.Width) / 2;
return rectF.Location;
}
private PointF ProcessXMinYMax(RectangleF rectF, RectangleF rectFView) {
rectF.X = rectF.X;
rectF.Y = rectF.Bottom - rectFView.Height;
return rectF.Location;
}
private PointF ProcessXMidYMax(RectangleF rectF, RectangleF rectFView) {
rectF.X = rectF.X + (rectF.Width - rectFView.Width) / 2;
rectF.Y = rectF.Bottom - rectFView.Height;
return rectF.Location;
}
private PointF ProcessXMaxYMax(RectangleF rectF, RectangleF rectFView) {
rectF.X = rectF.Right - rectFView.Height;
rectF.Y = rectF.Bottom - rectFView.Height;
return rectF.Location;
}
protected virtual void SetPen(Pen p, SvgAttributes attrs) { }
protected virtual Brush GetBrush(SvgAttributes attr) {
return null;
}
protected internal override void Dispose() { }
private float _F(string strValue) {
return float.Parse(strValue);
}
protected override void OnDrawStroke(Graphics g, GraphicsPath gp) { }
protected override void OnDrawFill(Graphics g, GraphicsPath gp) { }
protected override void OnDrawMarkers(Graphics g, GraphicsPath gp) { }
}
}

View File

@ -1,135 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.IO;
using System.Xml;
namespace ST.Library.Drawing.SvgRender
{
partial class SvgDocument
{
private static Type m_type_svg_element = typeof(SvgElement);
private static Regex m_reg_style_width = new Regex(@"\bwidth\s*:\s*(\.\d+|\d+(?:\.\d+))");
private static Regex m_reg_style_height = new Regex(@"\bheight\s*:\s*(\.\d+|\d+(?:\.\d+))");
private static Regex m_reg_number = new Regex(@"(-?(\.\d+|\d(?:\.\d+)?)+)");
private static Dictionary<string, Type> m_dic_target_type = new Dictionary<string, Type>();
static SvgDocument() {
var asm = Assembly.GetExecutingAssembly();
SvgDocument.RegisterType(asm);
}
internal static SvgElement CreateElement(string strTargetName) {
if (!m_dic_target_type.ContainsKey(strTargetName)) {
return null;
}
var obj = Activator.CreateInstance(m_dic_target_type[strTargetName]);
return (SvgElement)obj;
}
public static string[] GetTargetNames() {
return m_dic_target_type.Keys.ToArray();
}
public static bool UnRegisterType(string strTargetName) {
if (!m_dic_target_type.ContainsKey(strTargetName)) {
return false;
}
m_dic_target_type.Remove(strTargetName);
return true;
}
public static bool RegisterType(string strTargetName, Type type) {
return SvgDocument.RegisterType(strTargetName, type, true);
}
public static bool RegisterType(string strTargetName, Type type, bool bOverride) {
if (type.IsAbstract) {
throw new ArgumentException("Can not retister a abstract class!");
}
if (!(type.IsSubclassOf(m_type_svg_element))) {
throw new ArgumentException("The type is not a SvgElement!");
}
if (!m_dic_target_type.ContainsKey(strTargetName)) {
m_dic_target_type.Add(strTargetName, type);
return true;
}
if (!bOverride) {
return false;
}
m_dic_target_type[strTargetName] = type;
return true;
}
public static int RegisterType() {
var asm = Assembly.GetCallingAssembly();
return SvgDocument.RegisterType(asm, true);
}
public static int RegisterType(bool bOverride) {
var asm = Assembly.GetCallingAssembly();
return SvgDocument.RegisterType(asm, bOverride);
}
public static int RegisterType(string strFile) {
return SvgDocument.RegisterType(strFile, true);
}
public static int RegisterType(string strFile, bool bOverride) {
var asm = Assembly.LoadFrom(Path.GetFullPath(strFile));
return SvgDocument.RegisterType(asm, bOverride);
}
public static int RegisterType(Assembly asm) {
return SvgDocument.RegisterType(asm, true);
}
public static int RegisterType(Assembly asm, bool bOverride) {
int nCounter = 0;
var types = asm.GetTypes();
foreach (var t in types) {
if (t.IsAbstract) {
continue;
}
var attrs = t.GetCustomAttributes(false);
foreach (var a in attrs) {
if (!(a is SvgElementAttribute)) {
continue;
}
if (!t.IsSubclassOf(m_type_svg_element)) {
continue;
}
if (SvgDocument.RegisterType(((SvgElementAttribute)a).TargetName, t, bOverride)) {
nCounter++;
}
}
}
return nCounter;
}
//========================================================
public static SvgDocument FromXmlFile(string strFile) {
return SvgDocument.FromXml(File.ReadAllText(strFile));
}
public static SvgDocument FromXml(string strXml) {
XmlDocument xml = new XmlDocument();
xml.LoadXml(strXml);
return SvgDocument.FromXmlDocument(xml);
}
public static SvgDocument FromXmlDocument(XmlDocument xml) {
// TODO: comment element
var doc = xml.DocumentElement;
if (doc == null || doc.Name != "svg") {
throw new ArgumentException("Invalid svg document");
}
SvgDocument svg = new SvgDocument();
svg.InitElement(svg, null, doc);
return svg;
}
}
}

View File

@ -1,364 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
public abstract class SvgElement : IDisposable
{
private static Regex m_reg_url_id = new Regex(@"url\((?:'|"")?#(.*?)(?:'|"")?\)");
private static Regex m_reg_style = new Regex(@"([a-zA-Z][a-zA-z0-9\-]*)\s?:\s*(.*?)(?:;|$)");
public abstract string TargetName { get; }
/// <summary>
/// Specifies whether children of the current element are allowed to draw.
/// Such as: [defs]
/// </summary>
public abstract bool AllowElementDraw { get; }
public SvgDocument Document { get; private set; }
public string OuterXml { get; private set; }
public string InnerXml { get; private set; }
public string InnerText { get; private set; }
public SvgElement DomParent { get; private set; }
public SvgElement CurrentParent {
get {
if (TempParent != null) {
return this.TempParent;
}
return this.DomParent;
}
}
private SvgElement TempParent { get; set; }
public SvgAttributes Attributes { get; private set; }
public SvgElementCollection Elements { get; private set; }
public SvgElement() {
this.Attributes = new SvgAttributes();
this.Elements = new SvgElementCollection(1);
}
public SvgElement GetElementByID(string strID) {
foreach (var v in this.Elements) {
if (v.Attributes["id"] == strID) {
return v;
}
}
foreach (var v in this.Elements) {
var ret = v.GetElementByID(strID);
if (ret != null) {
return ret;
}
}
return null;
}
public List<SvgElement> GetElementsByClass(string strClassName) {
List<SvgElement> lst = new List<SvgElement>();
foreach (var v in this.Elements) {
if (v.Attributes["class"] == strClassName) {
lst.Add(v);
}
foreach (var e in v.GetElementsByClass(strClassName)) {
lst.Add(e);
}
}
return lst;
}
public List<SvgElement> GetElementsByTarget(string strTargetName) {
List<SvgElement> lst = new List<SvgElement>();
foreach (var v in this.Elements) {
if (v.TargetName == strTargetName) {
lst.Add(v);
}
foreach (var e in v.GetElementsByTarget(strTargetName)) {
lst.Add(e);
}
}
return lst;
}
internal void InitElement(SvgDocument doc, SvgElement parent, XmlNode node) {
this.Document = doc;
this.DomParent = parent;
this.OuterXml = node.OuterXml;
this.InnerXml = node.InnerXml;
this.InnerText = node.InnerText;
string strStyle = null;
foreach (XmlAttribute attr in node.Attributes) {
if (attr.Value == "inherit") {
continue;
}
switch (attr.Name) { // TODO: ..
//case "id":
//case "class":
case "style":
strStyle = attr.Value;
continue;
}
this.Attributes.Set(attr.Name, attr.Value);
this.OnInitAttribute(attr.Name, attr.Value);
}
if (!string.IsNullOrEmpty(strStyle)) {
foreach (Match m in m_reg_style.Matches(strStyle)) {
this.Attributes.Set(m.Groups[1].Value, m.Groups[2].Value);
this.OnInitAttribute(m.Groups[1].Value, m.Groups[2].Value);
}
}
foreach (XmlNode n in node.ChildNodes) {
if (n.LocalName[0] == '#') {
continue;
}
var ele = SvgDocument.CreateElement(n.LocalName);
if (ele == null) {
continue;
}
ele.InitElement(doc, this, n);
this.Elements.Add(ele);
}
this.OnInitElementCompleted();
}
protected void DrawElement(Graphics g, SvgElement ele, SvgElement tempParent) {
ele.TempParent = tempParent;
ele.DrawElement(g);
ele.TempParent = null;
}
internal protected virtual void DrawElement(Graphics g) {
GraphicsPath gp = this.GetDrawPath();// this.GetPath();
if (gp != null) {
using (gp) {
//gp.FillMode = SvgAttributes.GetString(this, "fill-rule") == "evenodd" ? FillMode.Alternate : FillMode.Winding;
string strOrder = SvgAttributes.GetString(this, "paint-order");// this.Attributes["paint-order"];
if (string.IsNullOrEmpty(strOrder)) {
strOrder = string.Empty;
}
using (var matrix = SvgAttributes.GetTransform(this, "transform", true)) {
gp.Transform(matrix);
bool bStrokeDrawed = false, bFillDrawed = false, bMarkersDrawed = false;
foreach (var v in strOrder.Split(' ')) {
switch (v) {
case "stroke":
this.OnDrawStroke(g, gp);
bStrokeDrawed = true;
break;
case "fill":
this.OnDrawFill(g, gp);
bFillDrawed = true;
break;
case "markers":
this.OnDrawMarkers(g, gp);
bMarkersDrawed = true;
break;
}
}
if (!bFillDrawed) {
this.OnDrawFill(g, gp);
}
if (!bStrokeDrawed) {
this.OnDrawStroke(g, gp);
}
if (!bMarkersDrawed) {
this.OnDrawMarkers(g, gp);
}
}
}
}
if (!this.AllowElementDraw) {
return;
}
foreach (var v in this.Elements) {
v.DrawElement(g);
}
}
protected virtual Dictionary<string, string> InitDefaultAttrs() {
return null;
}
protected virtual void OnInitElementCompleted() { }
internal protected abstract void OnInitAttribute(string strName, string strValue);
internal protected GraphicsPath GetDrawPath(SvgElement ele) {
this.TempParent = ele;
var gp = this.GetDrawPath();
this.TempParent = null;
return gp;
}
internal protected GraphicsPath GetDrawPath() {
GraphicsPath gp = this.GetPath();
if (gp == null) {
return null;
}
gp.FillMode = SvgAttributes.GetString(this, "fill-rule") == "evenodd" ? FillMode.Alternate : FillMode.Winding;
return gp;
}
public abstract GraphicsPath GetPath();
internal protected abstract void Dispose();
protected virtual void OnDrawStroke(Graphics g, GraphicsPath gp) {
Pen p = this.GetPen();
if (p == null) return;
using (p) {
g.DrawPath(p, gp);
}
}
protected virtual void OnDrawFill(Graphics g, GraphicsPath gp) {
Brush brush = this.GetBrush();
if (brush == null) return;
using (brush) {
g.FillPath(brush, gp);
}
}
protected virtual void OnDrawMarkers(Graphics g, GraphicsPath gp) { }
public Pen GetPen() {
var p = this.GetPen(this, this.GetStrokeAlpha());
if (p == null) {
return null;
}
this.SetPen(p);
return p;
}
public virtual Pen GetPen(SvgElement ele, float fAlpha) {
string strTemp = SvgAttributes.GetString(this, "stroke");
if (string.IsNullOrEmpty(strTemp)) {
return null;
}
Pen p = null;
Match m = m_reg_url_id.Match(strTemp);
if (m.Success) {
SvgElement svg_obj = this.Document.GetElementByID(m.Groups[1].Value);
if (svg_obj == null) {
return null;
}
p = svg_obj.GetPen(ele, fAlpha);
} else {
Color clr = SvgAttributes.GetColor(this, "stroke");
p = new Pen(Color.FromArgb((int)(clr.A * fAlpha), clr));
}
p.Width = SvgAttributes.GetSize(this, "stroke-width");
return p;
}
protected float GetStrokeAlpha() {
float fOpacity = SvgAttributes.GetOpacity(this, "opacity", true);
float fStrokeOpacity = SvgAttributes.GetFloat(this, "stroke-opacity");
fOpacity *= fStrokeOpacity;
if (fOpacity < 0) {
fOpacity = 0;
} else if (fOpacity > 1) {
fOpacity = 1;
}
return fOpacity;
}
protected float GetFillAlpha() {
float fOpacity = SvgAttributes.GetOpacity(this, "opacity", true);
float fStrokeOpacity = SvgAttributes.GetFloat(this, "fill-opacity");
return fOpacity * fStrokeOpacity;
}
protected virtual void SetPen(Pen p) {
switch (SvgAttributes.GetEnum(this, "stroke-linecap", true, new string[] { "round", "square", "butt" }, "butt")) {
case "round":
p.StartCap = LineCap.Round;
p.EndCap = LineCap.Round;
break;
case "square":
p.StartCap = LineCap.Square;
p.EndCap = LineCap.Square;
break;
case "butt":
default:
p.StartCap = LineCap.NoAnchor;
p.EndCap = LineCap.NoAnchor;
break;
}
switch (SvgAttributes.GetEnum(this, "stroke-linejoin", true, new string[] { "miter-clip", "bevel", "round", "miter" }, "miter")) {
case "miter-clip":
p.LineJoin = LineJoin.MiterClipped;
break;
case "bevel":
p.LineJoin = LineJoin.Bevel;
break;
case "round":
p.LineJoin = LineJoin.Round;
p.DashCap = DashCap.Round;
break;
case "miter":
default:
p.LineJoin = LineJoin.Miter;
break;
}
p.MiterLimit = SvgAttributes.GetFloat(this, "stroke-miterlimit");// this.GetFloat("stroke-miterlimit");
p.DashOffset = SvgAttributes.GetFloat(this, "stroke-dashoffset") / p.Width;// this.GetFloat("stroke-dashoffset");
float[] arr = SvgAttributes.GetSizeArray(this, "stroke-dasharray", true);
if (arr == null) return;
int nErrorCount = 0;
for (int i = 0; i < arr.Length; i++) {
if (arr[i] <= 0) {
nErrorCount++;
}
arr[i] = arr[i] / p.Width;
}
if (nErrorCount != 0) {
var temp = new float[arr.Length - nErrorCount];
for (int i = 0, j = 0; i < arr.Length; i++) {
if (arr[i] <= 0) continue;
temp[j++] = arr[i];
}
arr = temp;
}
if (arr != null) {
if (arr.Length % 2 != 0) {
float[] temp_arr = new float[arr.Length * 2];
for (int i = 0; i < temp_arr.Length; i++) {
temp_arr[i] = arr[i % arr.Length];
}
p.DashPattern = temp_arr;
} else {
p.DashPattern = arr;
}
}
}
public Brush GetBrush() {
return this.GetBrush(this, this.GetFillAlpha());
}
public virtual Brush GetBrush(SvgElement ele, float fAlpha) {
string strTemp = SvgAttributes.GetString(this, "fill");
if (string.IsNullOrEmpty(strTemp)) {
return null;
}
Brush brush = null;
Match m = m_reg_url_id.Match(strTemp);
if (m.Success) {
SvgElement svg_obj = this.Document.GetElementByID(m.Groups[1].Value);
if (svg_obj == null) {
return null;
}
brush = svg_obj.GetBrush(ele, fAlpha);
} else {
Color clr = SvgAttributes.GetColor(this, "fill");
clr = Color.FromArgb((int)(clr.A * fAlpha), clr);
brush = new SolidBrush(clr);
}
return brush;
}
void IDisposable.Dispose() {
this.Dispose();
}
}
}

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.Drawing.SvgRender
{
public class SvgElementAttribute : Attribute
{
public string TargetName { get; private set; }
public SvgElementAttribute(string strTargetName) {
this.TargetName = strTargetName;
}
}
}

View File

@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace ST.Library.Drawing.SvgRender
{
public sealed class SvgElementCollection : IEnumerable
{
public int Count { get; private set; }
private SvgElement[] m_arr;
internal SvgElementCollection(int capacity) {
m_arr = new SvgElement[capacity];
}
public SvgElement this[int nIndex] {
get {
if (nIndex < 0 || nIndex >= this.Count) {
throw new ArgumentOutOfRangeException("nIndex");
}
return m_arr[nIndex];
}
}
internal void Add(SvgElement ele) {
this.EnsureSpace(1);
m_arr[this.Count++] = ele;
}
private void EnsureSpace(int nCount) {
if (this.Count + nCount <= m_arr.Length) {
return;
}
SvgElement[] temp = new SvgElement[Math.Max(m_arr.Length << 1, this.Count + nCount)];
m_arr.CopyTo(temp, 0);
m_arr = temp;
}
public IEnumerator<SvgElement> GetEnumerator() {
for (int i = 0; i < this.Count; i++) {
yield return m_arr[i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
}
}

View File

@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("circle")]
public class SvgCircle : SvgElement
{
public override string TargetName {
get { return "circle"; }
}
public override bool AllowElementDraw {
get { return true; }
}
public float CX { get; set; }
public float CY { get; set; }
public float R { get; set; }
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "cx":
this.CX = SvgAttributes.GetSize(this, "cx");
break;
case "cy":
this.CY = SvgAttributes.GetSize(this, "cy");
break;
case "r":
this.R = SvgAttributes.GetSize(this, "r");
break;
}
}
public override GraphicsPath GetPath() {
GraphicsPath gp = new GraphicsPath();
RectangleF rectF = new RectangleF(
SvgAttributes.GetSize(this.CurrentParent, "x") + this.CX - this.R,
SvgAttributes.GetSize(this.CurrentParent, "y") + this.CY - this.R,
this.R * 2,
this.R * 2);
gp.AddEllipse(rectF);
return gp;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("defs")]
public class SvgDefs : SvgElement
{
public override string TargetName {
get { return "defs"; }
}
public override bool AllowElementDraw {
get { return false; }
}
protected internal override void OnInitAttribute(string strName, string strValue) { }
public override System.Drawing.Drawing2D.GraphicsPath GetPath() {
return null;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("ellipse")]
public class SvgEllipse : SvgElement
{
public override string TargetName {
get { return "ellipse"; }
}
public override bool AllowElementDraw {
get { return true; }
}
public float CX { get; set; }
public float CY { get; set; }
public float RX { get; set; }
public float RY { get; set; }
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "cx":
this.CX = SvgAttributes.GetSize(this, "cx");
break;
case "cy":
this.CY = SvgAttributes.GetSize(this, "cy");
break;
case "rx":
this.RX = SvgAttributes.GetSize(this, "rx");
break;
case "ry":
this.RY = SvgAttributes.GetSize(this, "ry");
break;
}
}
public override GraphicsPath GetPath() {
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(
SvgAttributes.GetSize(this.CurrentParent, "x") + this.CX - this.RX,
SvgAttributes.GetSize(this.CurrentParent, "y") + this.CY - this.RY,
this.RX * 2,
this.RY * 2);
return gp;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("g")]
public class SvgG : SvgElement
{
public override string TargetName {
get { return "g"; }
}
public override bool AllowElementDraw {
get { return true; }
}
protected internal override void OnInitAttribute(string strName, string strValue) { }
public override GraphicsPath GetPath() {
return null;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,66 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
public abstract class SvgGradientBrush : SvgElement
{
public override bool AllowElementDraw {
get { return false; }
}
public override GraphicsPath GetPath() { return null; }
protected internal override void OnInitAttribute(string strName, string strValue) { }
protected virtual ColorBlend GetColorBlend(float fAlpha, bool bClear) {
Color clr_start = SvgAttributes.GetColor(this.Elements[0], "stop-color", false, Color.Black);
Color clr_end = SvgAttributes.GetColor(this.Elements[this.Elements.Count - 1], "stop-color", false, Color.Black);
Color[] clr_arr = new Color[this.Elements.Count + 2];
float[] pos_arr = new float[clr_arr.Length];
pos_arr[pos_arr.Length - 1] = 1;
clr_arr[0] = Color.FromArgb((int)(clr_start.A * fAlpha), clr_start);
clr_arr[clr_arr.Length - 1] = Color.FromArgb((int)(clr_end.A * fAlpha), clr_end);
for (int i = 0; i < this.Elements.Count; i++) {
string strOffset = this.Elements[i].Attributes["offset"];
if (string.IsNullOrEmpty(strOffset)) {
pos_arr[i + 1] = pos_arr[i];
continue;
}
bool bFlag = false;
if (strOffset[strOffset.Length - 1] == '%') {
bFlag = true;
strOffset = strOffset.Substring(0, strOffset.Length - 1);
}
if (!SvgAttributes.CheckIsFloat(strOffset)) {
pos_arr[i + 1] = pos_arr[i];
continue;
}
pos_arr[i + 1] = float.Parse(strOffset);
if (bFlag) {
pos_arr[i + 1] /= 100;
}
clr_arr[i + 1] = SvgAttributes.GetColor(this.Elements[i], "stop-color", false, Color.Black);
clr_arr[i + 1] = Color.FromArgb((int)(clr_arr[i + 1].A * fAlpha), clr_arr[i + 1]);
}
int nIndex = 0, nLen = pos_arr.Length;
if (bClear) {
if (pos_arr[1] == 0) {
nLen--;
nIndex++;
}
if (pos_arr[pos_arr.Length - 2] == 1) {
nLen--;
}
}
ColorBlend cb = new ColorBlend(nLen);
Array.Copy(clr_arr, nIndex, cb.Colors, 0, nLen);
Array.Copy(pos_arr, nIndex, cb.Positions, 0, nLen);
return cb;
}
}
}

View File

@ -1,56 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("line")]
public class SvgLine : SvgElement
{
public override string TargetName {
get { return "line"; }
}
public override bool AllowElementDraw {
get { return true; }
}
public float X1 { get; private set; }
public float Y1 { get; private set; }
public float X2 { get; private set; }
public float Y2 { get; private set; }
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "x1":
this.X1 = SvgAttributes.GetSize(this, "x1");
break;
case "y1":
this.Y1 = SvgAttributes.GetSize(this, "y1");
break;
case "x2":
this.X2 = SvgAttributes.GetSize(this, "x2");
break;
case "y2":
this.Y2 = SvgAttributes.GetSize(this, "y2");
break;
}
}
public override GraphicsPath GetPath() {
GraphicsPath gp = new GraphicsPath();
gp.AddLine(
SvgAttributes.GetSize(this.CurrentParent, "x") + this.X1,
SvgAttributes.GetSize(this.CurrentParent, "y") + this.Y1,
SvgAttributes.GetSize(this.CurrentParent, "x") + this.X2,
SvgAttributes.GetSize(this.CurrentParent, "y") + this.Y2);
return gp;
}
protected internal override void Dispose() {
}
}
}

View File

@ -1,351 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
/*
* Note: This class implementation is not complete.
*/
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("linearGradient")]
public class SvgLinearGradient : SvgGradientBrush
{
public override string TargetName {
get { return "linearGradient"; }
}
public override Pen GetPen(SvgElement ele, float fAlpha) {
return new Pen(this.GetBrush(ele, fAlpha));
}
public override Brush GetBrush(SvgElement ele, float fAlpha) {
PointF ptFStart = PointF.Empty;
PointF ptFEnd = PointF.Empty;
RectangleF rectF = this.Document.ViewBox;
bool bFlag = SvgAttributes.GetString(this, "gradientUnits", true) == "userSpaceOnUse";
if (!bFlag) {
using (GraphicsPath gp = ele.GetPath()) {
rectF = gp.GetBounds();
}
}
if (this.Elements.Count <= 1) {
return new SolidBrush(SvgAttributes.GetColor(this.Elements[0], "stop-color", false, Color.Black));
}
using (Matrix mm = SvgAttributes.GetTransform(ele, "transform")) {
using (Matrix m = SvgAttributes.GetTransform(this, "gradientTransform")) {
mm.Multiply(m);
rectF.Width += Math.Abs(m.Elements[4] * 2);
rectF.Height += Math.Abs(m.Elements[5] * 2);
rectF.X -= Math.Abs(m.Elements[4]);
rectF.Y -= Math.Abs(m.Elements[5]);
ptFStart.X = this.GetX1Size(rectF, bFlag);
ptFStart.Y = this.GetY1Size(rectF, bFlag);
ptFEnd.X = this.GetX2Size(rectF, bFlag);
ptFEnd.Y = this.GetY2Size(rectF, bFlag);
if (ptFStart == ptFEnd) {
return null;
}
BrushInfo bi;
ColorBlend cb = this.GetColorBlend(fAlpha, false);
string strMethod = SvgAttributes.GetString(this, "spreadMethod");
if (string.IsNullOrEmpty(strMethod) || strMethod == "pad") {
if (ptFStart.X == ptFEnd.X) {
bi = this.SetColorBlendV(rectF, ptFStart, ptFEnd, cb);
} else if (ptFStart.Y == ptFEnd.Y) {
bi = this.SetColorBlendH(rectF, ptFStart, ptFEnd, cb);
} else {
bi = this.SetColorBlendB(rectF, ptFStart, ptFEnd, cb);
}
} else {
bi.Start = ptFStart;
bi.End = ptFEnd;
bi.ColorBlend = cb;
}
LinearGradientBrush brush = new LinearGradientBrush(bi.Start, bi.End, Color.Black, Color.Black);
brush.InterpolationColors = bi.ColorBlend;
if (SvgAttributes.GetString(this, "spreadMethod") != "repeat") {
brush.WrapMode = WrapMode.TileFlipX;
}
brush.MultiplyTransform(mm);
return brush;
}
}
}
private struct BrushInfo
{
public PointF Start;
public PointF End;
public ColorBlend ColorBlend;
}
private float GetX1Size(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["x1"];
if (string.IsNullOrEmpty(strText)) {
return rectF.X;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "x1", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.X + fTemp;
}
}
private float GetY1Size(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["y1"];
if (string.IsNullOrEmpty(strText)) {
return rectF.Y;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "y1", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.Y + fTemp;
}
}
private float GetX2Size(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["x2"];
if (string.IsNullOrEmpty(strText)) {
return rectF.Right;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "x2", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.X + fTemp;
}
}
private float GetY2Size(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["y2"];
if (string.IsNullOrEmpty(strText)) {
return rectF.Y;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "y2", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.Y + fTemp;
}
}
private BrushInfo GetColorBlend(RectangleF rectF, PointF ptF1, PointF ptF2) {
BrushInfo bi = new BrushInfo();
ColorBlend cb = new ColorBlend(this.Elements.Count + 2);
cb.Colors[0] = SvgAttributes.GetColor(this.Elements[0], "stop-color", false, Color.Black);
cb.Positions[this.Elements.Count + 1] = 1;
cb.Colors[this.Elements.Count + 1] = SvgAttributes.GetColor(this.Elements[this.Elements.Count - 1], "stop-color", false, Color.Black);
for (int i = 0; i < this.Elements.Count; i++) {
string strOffset = this.Elements[i].Attributes["offset"];
if (string.IsNullOrEmpty(strOffset)) {
cb.Positions[i + 1] = cb.Positions[i];
continue;
}
bool bFlag = false;
if (strOffset[strOffset.Length - 1] == '%') {
bFlag = true;
strOffset = strOffset.Substring(0, strOffset.Length - 1);
}
if (!SvgAttributes.CheckIsFloat(strOffset)) {
cb.Positions[i + 1] = cb.Positions[i];
continue;
}
cb.Positions[i + 1] = float.Parse(strOffset);
if (bFlag) {
cb.Positions[i + 1] /= 100;
}
cb.Colors[i + 1] = SvgAttributes.GetColor(this.Elements[i], "stop-color", false, Color.Black);
}
// y = ax + b -> a = (y2 - y1)/(x2 - x1)
float a_src = (ptF2.Y - ptF1.Y) / (ptF2.X - ptF1.X);
// b = y - ax;
float b_src = ptF2.Y - a_src * ptF2.X;
float angle = (float)(Math.PI / 180 * 90); // rotate 90deg
// b.x = a.x * cos (angle) + a.y * sin (angle)
// b.y = a.y * cos (angle) - a.x * sin (angle)
PointF ptF1_new = ptF1;
ptF1_new.X = (float)(ptF1.X * Math.Cos(angle) + ptF1.Y * Math.Sign(angle));
ptF1_new.Y = (float)(ptF1.Y * Math.Cos(angle) - ptF1.X * Math.Sign(angle));
PointF ptF2_new = ptF2;
ptF2_new.X = (float)(ptF2.X * Math.Cos(angle) + ptF2.Y * Math.Sign(angle));
ptF2_new.Y = (float)(ptF2.Y * Math.Cos(angle) - ptF2.X * Math.Sign(angle));
float a_rotate = (ptF2_new.Y - ptF1_new.Y) / (ptF2_new.X - ptF1_new.X);
float b_left = rectF.Y - a_rotate * rectF.X;
float b_right = rectF.Bottom - a_rotate * rectF.Right;
// a1 * x + b1 = a2 * x + b2 => x = (b2 - b1) / (a1 - a2)
float leftX = (b_left - b_src) / (a_src - a_rotate);
float leftY = a_rotate * leftX + b_left;
float rightX = (b_right - b_src) / (a_src - a_rotate);
float rightY = a_rotate * rightX + b_right;
float lenOld = (float)Math.Sqrt(Math.Pow(ptF2.X - ptF1.X, 2) + Math.Pow(ptF2.Y - ptF1.Y, 2));
float lenNew = (float)Math.Sqrt(Math.Pow(rightX - leftX, 2) + Math.Pow(rightY - leftY, 2));
float lenSeg = 0;
if (ptF1.X < ptF2.X) {
lenSeg = (float)Math.Sqrt(Math.Pow(ptF1.X - leftX, 2) + Math.Pow(ptF1.Y - leftY, 2));
} else {
lenSeg = (float)Math.Sqrt(Math.Pow(rightX - ptF2.X, 2) + Math.Pow(rightY - ptF2.Y, 2));
}
float fStart = lenSeg / lenNew;
float fIncrement = lenOld / lenNew;
for (int i = 1; i < cb.Positions.Length - 1; i++) {
cb.Positions[i] = fStart + cb.Positions[i] * fIncrement;
}
bi.Start = new PointF(leftX, leftY);
bi.End = new PointF(rightX, rightY);
bi.ColorBlend = cb;
return bi;
}
private BrushInfo SetColorBlendV(RectangleF rectF, PointF ptF1, PointF ptF2, ColorBlend cb) {
BrushInfo bi = new BrushInfo() {
ColorBlend = cb
};
float fMin = Math.Min(Math.Min(rectF.Y, ptF1.Y), ptF2.Y);
float fMax = Math.Max(Math.Max(rectF.Bottom, ptF1.Y), ptF2.Y);
float fLen = fMax - fMin;
float f = (ptF2.Y - ptF1.Y) / fLen;
float fStart = 0;
bi.Start.X = bi.End.X = ptF1.X;
if (f > 0) {
fStart = (ptF1.Y - fMin) / fLen;
bi.Start.Y = fMin;
bi.End.Y = fMax;
} else {
fStart = (fMax - ptF1.Y) / fLen;
bi.Start.Y = fMax;
bi.End.Y = fMin;
f = -f;
}
for (int i = 1; i < cb.Positions.Length - 1; i++) {
cb.Positions[i] = fStart + cb.Positions[i] * f;
}
return bi;
}
private BrushInfo SetColorBlendH(RectangleF rectF, PointF ptF1, PointF ptF2, ColorBlend cb) {
BrushInfo bi = new BrushInfo() {
ColorBlend = cb
};
float fMin = Math.Min(Math.Min(rectF.X, ptF1.X), ptF2.X);
float fMax = Math.Max(Math.Max(rectF.Right, ptF1.X), ptF2.X);
float fLen = fMax - fMin;
float f = (ptF2.X - ptF1.X) / fLen;
float fStart = 0;
bi.Start.Y = bi.End.Y = ptF1.Y;
if (f > 0) {
fStart = (ptF1.X - fMin) / fLen;
bi.Start.X = fMin;
bi.End.X = fMax;
} else {
fStart = (fMax - ptF1.X) / fLen;
bi.Start.X = fMax;
bi.End.X = fMin;
f = -f;
}
for (int i = 1; i < cb.Positions.Length - 1; i++) {
cb.Positions[i] = fStart + cb.Positions[i] * f;
}
return bi;
}
private BrushInfo SetColorBlendB(RectangleF rectF, PointF ptF1, PointF ptF2, ColorBlend cb) {
BrushInfo bi = new BrushInfo() {
ColorBlend = cb
};
// y = ax + b -> a = (y2 - y1)/(x2 - x1)
float a_src = (ptF2.Y - ptF1.Y) / (ptF2.X - ptF1.X);
// b = y - ax;
float b_src = ptF2.Y - a_src * ptF2.X;
float angle = (float)(Math.PI / 180 * 90); // rotate 90deg
// b.x = a.x * cos (angle) + a.y * sin (angle)
// b.y = a.y * cos (angle) - a.x * sin (angle)
float new_x1 = (float)(ptF1.X * Math.Cos(angle) + ptF1.Y * Math.Sign(angle));
float new_y1 = (float)(ptF1.Y * Math.Cos(angle) - ptF1.X * Math.Sign(angle));
float new_x2 = (float)(ptF2.X * Math.Cos(angle) + ptF2.Y * Math.Sign(angle));
float new_y2 = (float)(ptF2.Y * Math.Cos(angle) - ptF2.X * Math.Sign(angle));
// y = ax + b -> a = (y2 - y1)/(x2 - x1)
float a_rotate = (new_y2 - new_y1) / (new_x2 - new_x1);
PointF ptF1_temp = ptF1, ptF2_temp = ptF2;
if (ptF1_temp.X > ptF2_temp.X) {
var temp = ptF1_temp;
ptF1_temp = ptF2_temp;
ptF2_temp = temp;
}
float b_left = 0, b_right = 0;
if (ptF2_temp.Y > ptF1_temp.Y) { // check the boundary
b_left = rectF.Y - a_rotate * rectF.X;
b_right = rectF.Bottom - a_rotate * rectF.Right;
} else {
b_left = rectF.Bottom - a_rotate * rectF.Left;
b_right = rectF.Y - a_rotate * rectF.Right;
}
// Get the line equation focus -> a1 * x + b1 = a2 * x + b2 => x = (b2 - b1) / (a1 - a2)
float leftX = (b_left - b_src) / (a_src - a_rotate);
float leftY = a_rotate * leftX + b_left; // y = ax + b
float rightX = (b_right - b_src) / (a_src - a_rotate);
float rightY = a_rotate * rightX + b_right; // y = ax + b
float lenOld = (float)Math.Sqrt(Math.Pow(ptF2.X - ptF1.X, 2) + Math.Pow(ptF2.Y - ptF1.Y, 2));
float lenNew = (float)Math.Sqrt(Math.Pow(rightX - leftX, 2) + Math.Pow(rightY - leftY, 2));
float fStart = 0;
if (ptF1.X < ptF2.X) {
bi.Start = new PointF(leftX, leftY);
bi.End = new PointF(rightX, rightY);
fStart = (float)Math.Sqrt(Math.Pow(ptF1.X - leftX, 2) + Math.Pow(ptF1.Y - leftY, 2)) / lenNew;
} else {
bi.Start = new PointF(rightX, rightY);
bi.End = new PointF(leftX, leftY);
fStart = (float)Math.Sqrt(Math.Pow(rightX - ptF1.X, 2) + Math.Pow(rightY - ptF1.Y, 2)) / lenNew;
}
float f = lenOld / lenNew;
for (int i = 1; i < cb.Positions.Length - 1; i++) {
cb.Positions[i] = fStart + cb.Positions[i] * f;
}
bi.ColorBlend = cb;
return bi;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,196 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
/*
* Note: This code was translated from https://github.com/fontello/svgpath/blob/master/lib/a2c.js
* Time: 2022-02-24
*/
namespace ST.Library.Drawing.SvgRender
{
partial class SvgPath
{
// Convert an arc to a sequence of cubic bezier curves
private const double TAU = Math.PI * 2;
/* eslint-disable space-infix-ops */
// Calculate an angle between two unit vectors
//
// Since we measure angle between radii of circular arcs,
// we can use simplified math (without length normalization)
//
private static double UnitVectorAngle(double x1, double y1, double x2, double y2) {
var sign = (x1 * y2 - y1 * x2 < 0) ? -1 : 1;
var dot = x1 * x2 + y1 * y2;
// Add this to work with arbitrary vectors:
// dot /= Math.Sqrt(x1 * x1 + y1 * y1) * Math.Sqrt(x2 * x2 + y2 * y2);
// rounding errors, e.g. -1.0000000000000002 can screw up this
if (dot > 1.0) { dot = 1.0F; }
if (dot < -1.0) { dot = -1.0F; }
return sign * Math.Acos(dot);
}
// Convert from endpoint to center parameterization,
// see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
//
// Return [cx, cy, theta, delta_theta]
//
private static double[] GetArcCenter(double x1, double y1, double x2, double y2, double rx, double ry, bool isLarge, bool isSweep, double sin_phi, double cos_phi) {
// Step 1.
//
// Moving an ellipse so origin will be the middlepoint between our two
// points. After that, rotate it to line up ellipse axes with coordinate
// axes.
//
var x1p = cos_phi * (x1 - x2) / 2 + sin_phi * (y1 - y2) / 2;
var y1p = -sin_phi * (x1 - x2) / 2 + cos_phi * (y1 - y2) / 2;
var rx_sq = rx * rx;
var ry_sq = ry * ry;
var x1p_sq = x1p * x1p;
var y1p_sq = y1p * y1p;
// Step 2.
//
// Compute coordinates of the centre of this ellipse (cx', cy')
// in the new coordinate system.
//
double radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq);
if (radicant < 0) {
// due to rounding errors it might be e.g. -1.3877787807814457e-17
radicant = 0;
}
radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq);
radicant = Math.Sqrt(radicant) * (isLarge == isSweep ? -1 : 1);
var cxp = radicant * rx / ry * y1p;
var cyp = radicant * -ry / rx * x1p;
// Step 3.
//
// Transform back to get centre coordinates (cx, cy) in the original
// coordinate system.
//
var cx = cos_phi * cxp - sin_phi * cyp + (x1 + x2) / 2;
var cy = sin_phi * cxp + cos_phi * cyp + (y1 + y2) / 2;
// Step 4.
//
// Compute angles (theta, delta_theta).
//
var v1x = (x1p - cxp) / rx;
var v1y = (y1p - cyp) / ry;
var v2x = (-x1p - cxp) / rx;
var v2y = (-y1p - cyp) / ry;
var theta = UnitVectorAngle(1, 0, v1x, v1y);
var delta_theta = UnitVectorAngle(v1x, v1y, v2x, v2y);
if (!isSweep && delta_theta > 0) {
delta_theta -= TAU;
}
if (isSweep && delta_theta < 0) {
delta_theta += TAU;
}
return new double[] { cx, cy, theta, delta_theta };
}
//
// Approximate one unit arc segment with bezier curves,
// see http://math.stackexchange.com/questions/873224
//
private static double[] ApproximateUnitArc(double theta, double delta_theta) {
var alpha = Math.Tan(delta_theta / 4) * 4 / 3;
var x1 = Math.Cos(theta);
var y1 = Math.Sin(theta);
var x2 = Math.Cos(theta + delta_theta);
var y2 = Math.Sin(theta + delta_theta);
return new double[] { x1, y1, x1 - y1 * alpha, y1 + x1 * alpha, x2 + y2 * alpha, y2 - x2 * alpha, x2, y2 };
}
/// <summary>
/// Convert an arc to a sequence of cubic bezier curves
/// </summary>
/// <param name="ptF">Start point</param>
/// <param name="rx">Ellipse X Radius</param>
/// <param name="ry">Ellipse Y Radius</param>
/// <param name="angle">xAxisRotate</param>
/// <param name="isLarge">LargeArcFlag</param>
/// <param name="isSweep">SweepFlag</param>
/// <param name="x">End X</param>
/// <param name="y">End Y</param>
/// <returns>The cubic bezier curve points list</returns>
public static List<double[]> ArcToBezier(PointF ptF, double rx, double ry, double angle, bool isLarge, bool isSweep, double x, double y) {
List<double[]> lst = new List<double[]>();
var sin_phi = Math.Sin(angle * TAU / 360);
var cos_phi = Math.Cos(angle * TAU / 360);
// Make sure radii are valid
var x1p = cos_phi * (ptF.X - x) / 2 + sin_phi * (ptF.Y - y) / 2;
var y1p = -sin_phi * (ptF.X - x) / 2 + cos_phi * (ptF.Y - y) / 2;
if (x1p.Equals(0) && y1p.Equals(0)) {
// we're asked to draw line to itself
return lst;
}
if (rx.Equals(0) || ry.Equals(0)) {
// one of the radii is zero
return lst;
}
// Compensate out-of-range radii
//
rx = Math.Abs(rx);
ry = Math.Abs(ry);
var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
if (lambda > 1) {
rx *= Math.Sqrt(lambda);
ry *= Math.Sqrt(lambda);
}
// Get center parameters (cx, cy, theta1, delta_theta)
//
var cc = GetArcCenter(ptF.X, ptF.Y, x, y, rx, ry, isLarge, isSweep, sin_phi, cos_phi);
var result = lst;
var theta1 = cc[2];
var delta_theta = cc[3];
// Split an arc to multiple segments, so each segment
// will be less than τ/4 (= 90°)
//
var segments = Math.Max(Math.Ceiling(Math.Abs(delta_theta) / (TAU / 4)), 1);
delta_theta /= segments;
for (var i = 0; i < segments; i++) {
lst.Add(ApproximateUnitArc(theta1, delta_theta));
theta1 += delta_theta;
}
// We have a bezier approximation of a unit circle,
// now need to transform back to the original ellipse
foreach (var p in lst) {
for (var i = 0; i < p.Length; i += 2) {
double temp_x = p[i], temp_y = p[i + 1];
temp_x *= rx;
temp_y *= ry;
var xp = cos_phi * temp_x - sin_phi * temp_y;
var yp = sin_phi * temp_x + cos_phi * temp_y;
p[i] = xp + cc[0];
p[i + 1] = yp + cc[1];
}
}
return lst;
}
}
}

View File

@ -1,289 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Text.RegularExpressions;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("path")]
public partial class SvgPath : SvgElement
{
private static Regex m_reg_d = new Regex(@"[a-zA-Z]|[+-]?(\.\d+|\d+(\.\d+)?)([eE]-\d+)?");
public override string TargetName {
get { return "path"; }
}
public override bool AllowElementDraw {
get { return true; }
}
private string _D;
public string D {
get { return _D; }
set {
m_strs_d = this.SetD(value);
_D = string.Join(" ", m_strs_d);
}
}
private string[] m_strs_d;
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "d":
this.D = strValue;
break;
}
}
private string[] SetD(string strD) {
var ms = m_reg_d.Matches(strD);
string[] str_arr = new string[ms.Count];
int nIndex = 0;
foreach (Match m in ms) {
str_arr[nIndex++] = m.Value;
}
return str_arr;
}
public override GraphicsPath GetPath() {
GraphicsPath gp = new GraphicsPath();
PointF ptf_last = new PointF();
PointF ptf_last_m = new PointF();
PointF[] ptfs_bezier = new PointF[4];
string[] args = m_strs_d;
string strCmd = "l";
for (int i = 0; i < args.Length; i++) {
if (SvgAttributes.CheckIsFloat(args[i])) {
i--; //use last command
} else {
strCmd = args[i];
}
switch (strCmd) {
case "m": //moveto
case "M":
ptf_last = this.MoveTo(strCmd == "M", ptf_last, _F(args[i + 1]), _F(args[i + 2]));
i += 2;
strCmd = strCmd == "m" ? "l" : "L"; // set the last command to "l"
if (i > 0) {
gp.CloseFigure();
}
ptf_last_m = ptf_last;
break;
case "l": //lineto
case "L":
ptf_last = this.LineTo(strCmd == "L", gp, ptf_last, _F(args[i + 1]), _F(args[i + 2]));
i += 2;
break;
case "h": //horizontal lineto
case "H":
ptf_last = this.HorizontalLineTo(strCmd == "H", gp, ptf_last, _F(args[++i]));
//gp.CloseFigure();
break;
case "v": //vertical lineto
case "V":
ptf_last = this.VerticalLineTo(strCmd == "V", gp, ptf_last, _F(args[++i]));
//gp.CloseFigure();
break;
case "c": //curveto
case "C":
ptfs_bezier[0] = ptf_last;
i++;
for (int j = 0; j < 3; j++) {
ptfs_bezier[j + 1].X = float.Parse(args[i++]);
ptfs_bezier[j + 1].Y = float.Parse(args[i++]);
}
i--;
ptf_last = this.CurveTo(strCmd == "C", gp, ptfs_bezier);
break;
case "s": //smooth curveto
case "S":
if (ptfs_bezier[3] == ptf_last) { // so .. the last command not a curve command
ptfs_bezier[0] = ptfs_bezier[3];
ptfs_bezier[1].X = ptfs_bezier[3].X + ptfs_bezier[3].X - ptfs_bezier[2].X;
ptfs_bezier[1].Y = ptfs_bezier[3].Y + ptfs_bezier[3].Y - ptfs_bezier[2].Y;
} else {
ptfs_bezier[0].X = ptfs_bezier[1].X = ptf_last.X;
ptfs_bezier[0].Y = ptfs_bezier[1].Y = ptf_last.Y;
}
i++;
for (int j = 0; j < 2; j++) {
ptfs_bezier[j + 2].X = float.Parse(args[i++]);
ptfs_bezier[j + 2].Y = float.Parse(args[i++]);
}
i--;
ptf_last = this.SmoothCurveTo(strCmd == "S", gp, ptfs_bezier);
break;
case "q": //quadratic bezier curveto
case "Q":
ptfs_bezier[0] = ptf_last;
i++;
for (int j = 0; j < 2; j++) {
ptfs_bezier[j + 2].X = float.Parse(args[i++]);
ptfs_bezier[j + 2].Y = float.Parse(args[i++]);
}
ptfs_bezier[1] = ptfs_bezier[2];
i--;
ptf_last = this.QuadraticBezierCurveTo(strCmd == "Q", gp, ptfs_bezier);
break;
case "t": //smooth quadratic bezier curveto
case "T":
ptfs_bezier[0] = ptfs_bezier[3];
ptfs_bezier[1].X = ptfs_bezier[3].X + ptfs_bezier[3].X - ptfs_bezier[2].X;
ptfs_bezier[1].Y = ptfs_bezier[3].Y + ptfs_bezier[3].Y - ptfs_bezier[2].Y;
ptfs_bezier[3].X = _F(args[i + 1]);
ptfs_bezier[3].Y = _F(args[i + 2]);
ptfs_bezier[2] = ptfs_bezier[1];
ptf_last = this.QuadraticBezierCurveTo(strCmd == "T", gp, ptfs_bezier);
i += 2;
break;
case "a": //elliptical Arc
case "A":
ptf_last = this.EllipticalArc(strCmd == "A",
gp, ptf_last,
_F(args[i + 1]),
_F(args[i + 2]),
_F(args[i + 3]),
args[i + 4] != "0",
args[i + 5] != "0",
_F(args[i + 6]),
_F(args[i + 7]));
i += 7;
break;
case "z": //close path
case "Z":
gp.CloseFigure();
ptf_last = ptf_last_m;
strCmd = "l"; // set the last command to "l"
break;
}
}
return gp;
}
protected internal override void Dispose() { }
private float _F(string strText) {
if (!SvgAttributes.CheckIsFloat(strText)) {
return 0;
}
return float.Parse(strText);
}
private PointF MoveTo(bool isAbsolute, PointF ptF, float x, float y) {
if (!isAbsolute) {
ptF.X += x;
ptF.Y += y;
} else {
ptF.X = x;
ptF.Y = y;
}
return ptF;
}
private PointF LineTo(bool isAbsolute, GraphicsPath gp, PointF ptF, float x, float y) {
if (!isAbsolute) {
gp.AddLine(ptF.X, ptF.Y, ptF.X + x, ptF.Y + y);
ptF.X += x;
ptF.Y += y;
} else {
gp.AddLine(ptF.X, ptF.Y, x, y);
ptF.X = x;
ptF.Y = y;
}
return ptF;
}
private PointF HorizontalLineTo(bool isAbsolute, GraphicsPath gp, PointF ptF, float x) {
if (!isAbsolute) {
gp.AddLine(ptF.X, ptF.Y, ptF.X + x, ptF.Y);
ptF.X += x;
} else {
gp.AddLine(ptF.X, ptF.Y, x, ptF.Y);
ptF.X = x;
}
return ptF;
}
private PointF VerticalLineTo(bool isAbsolute, GraphicsPath gp, PointF ptF, float y) {
if (!isAbsolute) {
gp.AddLine(ptF.X, ptF.Y, ptF.X, ptF.Y + y);
ptF.Y += y;
} else {
gp.AddLine(ptF.X, ptF.Y, ptF.X, y);
ptF.Y = y;
}
return ptF;
}
private PointF CurveTo(bool isAbsolute, GraphicsPath gp, PointF[] ptFs) {
if (!isAbsolute) {
ptFs[1].X += ptFs[0].X;
ptFs[1].Y += ptFs[0].Y;
ptFs[2].X += ptFs[0].X;
ptFs[2].Y += ptFs[0].Y;
ptFs[3].X += ptFs[0].X;
ptFs[3].Y += ptFs[0].Y;
}
gp.AddBeziers(ptFs);
return ptFs[3];
}
private PointF SmoothCurveTo(bool isAbsolute, GraphicsPath gp, PointF[] ptFs) {
if (!isAbsolute) {
ptFs[2].X += ptFs[0].X;
ptFs[2].Y += ptFs[0].Y;
ptFs[3].X += ptFs[0].X;
ptFs[3].Y += ptFs[0].Y;
}
gp.AddBeziers(ptFs);
return ptFs[3];
}
private PointF QuadraticBezierCurveTo(bool isAbsolute, GraphicsPath gp, PointF[] ptFs) {
if (!isAbsolute) {
ptFs[1].X += ptFs[0].X;
ptFs[1].Y += ptFs[0].Y;
ptFs[2].X += ptFs[0].X;
ptFs[2].Y += ptFs[0].Y;
ptFs[3].X += ptFs[0].X;
ptFs[3].Y += ptFs[0].Y;
}
var temp = ptFs[2];
// from https://stackoverflow.com/questions/3162645/convert-a-quadratic-bezier-to-a-cubic-one
// CP1 = QP0 + 2/3 *(QP1-QP0)
// CP2 = QP2 + 2/3 *(QP1-QP2)
// Note: ptFs -> [P0, P1, P1, P2] -> ptFs[1] == ptFs[2] and ptFs[1,2] need to calc.
ptFs[1].X = ptFs[0].X + (2 / 3F * (ptFs[1].X - ptFs[0].X));
ptFs[1].Y = ptFs[0].Y + (2 / 3F * (ptFs[1].Y - ptFs[0].Y));
// ---------------------------------------------------------------------------------
ptFs[2].X = ptFs[3].X + (2 / 3F * (ptFs[2].X - ptFs[3].X));
ptFs[2].Y = ptFs[3].Y + (2 / 3F * (ptFs[2].Y - ptFs[3].Y));
gp.AddBeziers(ptFs);
ptFs[2] = temp;
return ptFs[3];
}
private PointF EllipticalArc(bool isAbsolute, GraphicsPath gp, PointF ptF, float rx, float ry, float angle, bool isLargArc, bool isSweep, float x, float y) {
if (!isAbsolute) {
x += ptF.X;
y += ptF.Y;
}
// Convert arc to bezier point list
var lst_points = SvgPath.ArcToBezier(ptF, rx, ry, angle, isLargArc, isSweep, x, y);
foreach (var ps in lst_points) {
ptF.X = (float)ps[6];
ptF.Y = (float)ps[7];
gp.AddBezier(
(float)ps[0], (float)ps[1],
(float)ps[2], (float)ps[3],
(float)ps[4], (float)ps[5],
ptF.X, ptF.Y);
}
return ptF;
}
}
}

View File

@ -1,73 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("polygon")]
public class SvgPolygon : SvgElement
{
private static Regex m_reg_num = new Regex(@"[+-]?(\.\d+|\d+(\.\d+)?)([eE]-\d+)?");
public override string TargetName {
get { return "polygon"; }
}
public override bool AllowElementDraw {
get { return true; }
}
private string _Points;
public string Points {
get { return _Points; }
private set {
m_points = this.SetPoints(value);
string[] str_arr = new string[m_points.Length];
for (int i = 0; i < m_points.Length; i++) {
str_arr[i] = m_points[i].X + "," + m_points[i].Y;
}
_Points = string.Join(" ", str_arr);
}
}
private PointF[] m_points;
public SvgPolygon() {
this.Attributes.Set("fill", "black");
}
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "points":
this.Points = strValue;
break;
}
}
public override GraphicsPath GetPath() {
if (m_points == null || m_points.Length < 1) {
return null;
}
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon(m_points);
return gp;
}
private PointF[] SetPoints(string strPoints) {
var ms = m_reg_num.Matches(strPoints);
PointF[] ptFs = new PointF[ms.Count / 2];
for (int i = 0, j = 0; i < ms.Count; i += 2, j++) {
ptFs[j].X = float.Parse(ms[i].Value);
ptFs[j].Y = float.Parse(ms[i + 1].Value);
}
return ptFs;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,73 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("polyline")]
public class SvgPolyline : SvgElement
{
private static Regex m_reg_num = new Regex(@"[+-]?(\.\d+|\d+(\.\d+)?)([eE]-\d+)?");
public override string TargetName {
get { return "polygon"; }
}
public override bool AllowElementDraw {
get { return true; }
}
private string _Points;
public string Points {
get { return _Points; }
private set {
m_points = this.SetPoints(value);
string[] str_arr = new string[m_points.Length];
for (int i = 0; i < m_points.Length; i++) {
str_arr[i] = m_points[i].X + "," + m_points[i].Y;
}
_Points = string.Join(" ", str_arr);
}
}
private PointF[] m_points;
public SvgPolyline() {
this.Attributes.Set("fill", "black");
}
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "points":
this.Points = strValue;
break;
}
}
public override GraphicsPath GetPath() {
if (m_points == null || m_points.Length < 1) {
return null;
}
GraphicsPath gp = new GraphicsPath();
gp.AddLines(m_points);
return gp;
}
private PointF[] SetPoints(string strPoints) {
var ms = m_reg_num.Matches(strPoints);
PointF[] ptFs = new PointF[ms.Count / 2];
for (int i = 0, j = 0; i < ms.Count; i += 2, j++) {
ptFs[j].X = float.Parse(ms[i].Value);
ptFs[j].Y = float.Parse(ms[i + 1].Value);
}
return ptFs;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,229 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
/*
* Note: This class implementation is not complete.
*/
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("radialGradient")]
public class SvgRadialGradient : SvgGradientBrush
{
public override string TargetName {
get { return "radialGradient"; }
}
public override bool AllowElementDraw {
get { return false; }
}
public SvgRadialGradient() {
this.Attributes.Set("cx", "50%");
this.Attributes.Set("cy", "50%");
this.Attributes.Set("r", "50%");
this.Attributes.Set("fx", "50%");
this.Attributes.Set("fy", "50%");
this.Attributes.Set("fr", "0%");
}
protected internal override void OnInitAttribute(string strName, string strValue) { }
public override GraphicsPath GetPath() { return null; }
protected internal override void Dispose() { }
private float m_cx;
private float m_cy;
private float m_r;
private float m_fx;
private float m_fy;
private float m_fr; // not implemented
public override Pen GetPen(SvgElement ele, float fAlpha) {
return new Pen(this.GetBrush(ele, fAlpha));
}
public override Brush GetBrush(SvgElement ele, float fAlpha) {
if (this.Elements.Count <= 1) {
return new SolidBrush(SvgAttributes.GetColor(this.Elements[0], "stop-color", false, Color.Black));
}
RectangleF rectF = this.Document.ViewBox;
bool bFlag = SvgAttributes.GetString(this, "gradientUnits", true) == "userSpaceOnUse";
if (!bFlag) {
using (GraphicsPath gp = ele.GetPath()) {
rectF = gp.GetBounds();
}
}
m_cx = this.GetCXSize(rectF, bFlag);
m_cy = this.GetCYSize(rectF, bFlag);
m_fx = this.GetFXSize(rectF, bFlag);
m_fy = this.GetFYSize(rectF, bFlag);
m_r = this.GetRSize(rectF, bFlag);
if (m_r == 0) {
if (this.Elements.Count != 0) {
return new SolidBrush(SvgAttributes.GetColor(this.Elements[this.Elements.Count - 1], "stop-color", false, Color.Black));
}
return null;
}
using (Matrix mm = SvgAttributes.GetTransform(ele, "transform")) {
using (Matrix m = SvgAttributes.GetTransform(this, "gradientTransform")) {
mm.Multiply(m);
ColorBlend cb = this.GetColorBlend(fAlpha, true);
this.SetColorBlend(rectF, cb, m.Elements[4], m.Elements[5]);
for (int i = 0; i < cb.Positions.Length / 2; i++) {
var temp = cb.Colors[i];
cb.Colors[i] = cb.Colors[cb.Colors.Length - 1 - i];
cb.Colors[cb.Colors.Length - 1 - i] = temp;
}
if (SvgAttributes.GetString(this, "spreadMethod") == "pad") {
// not implemented
} else {
// not implemented
}
using (GraphicsPath gp_e = new GraphicsPath()) {
gp_e.AddEllipse(new RectangleF(m_cx - m_r, m_cy - m_r, 2 * m_r, 2 * m_r));
PathGradientBrush brush = new PathGradientBrush(gp_e);
brush.CenterPoint = new PointF(m_fx, m_fy);
brush.InterpolationColors = cb;
float tx = this.Document.XScale < 1 ? mm.Elements[4] * (this.Document.XScale - 1) : 0;
float ty = this.Document.YScale < 1 ? mm.Elements[5] * (this.Document.YScale - 1) : 0;
mm.Translate(tx, ty);
brush.MultiplyTransform(mm);
return brush;
}
}
}
}
private float GetCXSize(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["cx"];
if (string.IsNullOrEmpty(strText)) {
return rectF.X + rectF.Width / 2;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "cx", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.X + fTemp;
}
}
private float GetCYSize(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["cy"];
if (string.IsNullOrEmpty(strText)) {
return rectF.Y + rectF.Height / 2;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "cy", false, 0);
if (!bUserSpace)
fTemp *= rectF.Height;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.Y + fTemp;
}
}
private float GetRSize(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["r"];
if (string.IsNullOrEmpty(strText)) {
return rectF.Width / 2;
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "r", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
return fTemp;
}
private float GetFXSize(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["fx"];
if (string.IsNullOrEmpty(strText)) {
return this.GetCXSize(rectF, bUserSpace);
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Width * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "fx", false, 0);
if (!bUserSpace)
fTemp *= rectF.Width;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.X + fTemp;
}
}
private float GetFYSize(RectangleF rectF, bool bUserSpace) {
string strText = this.Attributes["fy"];
if (string.IsNullOrEmpty(strText)) {
return this.GetCYSize(rectF, bUserSpace);
}
float fTemp = 0;
if (strText[strText.Length - 1] == '%') {
fTemp = rectF.Height * float.Parse(strText.Substring(0, strText.Length - 1)) / 100;
} else {
fTemp = SvgAttributes.GetSize(this, "fy", false, 0);
if (!bUserSpace)
fTemp *= rectF.Height;
}
if (bUserSpace) {
return fTemp;
} else {
return rectF.Y + fTemp;
}
}
private void SetColorBlend(RectangleF rectF, ColorBlend cb, float translateX, float translateY) {
float r_new = rectF.Width + rectF.Height + Math.Abs(translateX) + Math.Abs(translateY);
if (m_cx > rectF.Right) r_new += m_cx - rectF.Right;
if (m_cx < rectF.X) r_new += rectF.X - m_cx;
if (m_cy > rectF.Bottom) r_new += m_cy - rectF.Bottom;
if (m_cy < rectF.Y) r_new += rectF.Y - m_cy;
float fStart = (r_new - m_r) / r_new;
for (int i = 0; i < cb.Positions.Length; i++) {
cb.Positions[i] = 1 - cb.Positions[i];
}
for (int i = 0; i < cb.Positions.Length / 2; i++) {
var temp = cb.Positions[i];
cb.Positions[i] = cb.Positions[cb.Positions.Length - 1 - i];
cb.Positions[cb.Positions.Length - 1 - i] = temp;
}
Color[] clr_arr = new Color[cb.Colors.Length + 1];
float[] pos_arr = new float[cb.Positions.Length + 1];
Array.Copy(cb.Colors, 0, clr_arr, 0, cb.Colors.Length);
Array.Copy(cb.Positions, 0, pos_arr, 1, cb.Positions.Length);
clr_arr[clr_arr.Length - 1] = clr_arr[clr_arr.Length - 2];
cb.Positions = pos_arr;
cb.Colors = clr_arr;
for (int i = 1; i < cb.Positions.Length - 1; i++) {
cb.Positions[i] = fStart + (1 - fStart) * cb.Positions[i];
}
m_r = r_new;
m_fx = m_cx + (m_fx - m_cx) * (fStart);
m_fy = m_cy + (m_fy - m_cy) * (fStart);
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("rect")]
public class SvgRect : SvgElement
{
public override string TargetName {
get { return "rect"; }
}
public override bool AllowElementDraw {
get { return true; }
}
public float X { get; private set; }
public float Y { get; private set; }
public float Width { get; private set; }
public float Height { get; private set; }
public float RX { get; private set; }
public float RY { get; private set; }
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "x":
this.X = SvgAttributes.GetSize(this, "x");
break;
case "y":
this.Y = SvgAttributes.GetSize(this, "y");
break;
case "width":
this.Width = SvgAttributes.GetSize(this, "width");
break;
case "height":
this.Height = SvgAttributes.GetSize(this, "height");
break;
case "rx":
this.RX = SvgAttributes.GetSize(this, "rx");
break;
case "ry":
this.RY = SvgAttributes.GetSize(this, "ry");
break;
}
}
public override GraphicsPath GetPath() {
return this.GetRoundRectPath(
SvgAttributes.GetSize(this.CurrentParent, "x") + this.X,
SvgAttributes.GetSize(this.CurrentParent, "y") + this.Y,
this.Width,
this.Height,
this.RX,
this.RY);
}
protected internal override void Dispose() { }
private GraphicsPath GetRoundRectPath(float nX, float nY, float nWidth, float nHeight, float nRX, float nRY) {
GraphicsPath gp = new GraphicsPath();
if (nRX == 0 || nRY == 0) {
gp.AddRectangle(new RectangleF(nX, nY, nWidth, nHeight));
} else {
nRX *= 2;
nRY *= 2;
if (nRX > nWidth) {
nRX = nWidth;
}
if (nRY > nHeight) {
nRY = nHeight;
}
gp.AddArc(nX, nY, nRX, nRY, 180, 90);
gp.AddArc(nX + nWidth - nRX, nY, nRX, nRY, 270, 90);
gp.AddArc(nX + nWidth - nRX, nY + nHeight - nRY, nRX, nRY, 0, 90);
gp.AddArc(nX, nY + nHeight - nRY, nRX, nRY, 90, 90);
gp.CloseFigure();
}
return gp;
}
}
}

View File

@ -1,29 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("stop")]
public class SvgStop : SvgElement
{
public override string TargetName {
get { return "stop"; }
}
public override bool AllowElementDraw {
get { return false; }
}
protected internal override void OnInitAttribute(string strName, string strValue) { }
public override GraphicsPath GetPath() {
return null;
}
protected internal override void Dispose() { }
}
}

View File

@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
namespace ST.Library.Drawing.SvgRender
{
[SvgElement("use")]
public class SvgUse : SvgElement
{
public override string TargetName {
get { return "use"; }
}
public override bool AllowElementDraw {
get { return true; }
}
public string LinkID { get; private set; }
protected internal override void OnInitAttribute(string strName, string strValue) {
switch (strName) {
case "href":
case "xlink:href":
if(string.IsNullOrEmpty(strValue) || strValue.Length < 2){
return;
}
if (strValue[0] != '#') {
return;
}
this.LinkID = strValue.Substring(1);
break;
}
}
protected internal override void DrawElement(System.Drawing.Graphics g) {
if (string.IsNullOrEmpty(this.LinkID)) {
return;
}
var ele = this.Document.GetElementByID(this.LinkID);
if (ele == null) {
return;
}
this.DrawElement(g, ele, this);
}
public override GraphicsPath GetPath() { return null; }
protected internal override void Dispose() { }
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
public struct FindInfo
{
public bool Find;
public int IndexOfLine;
public int IndexOfCharInLine;
public int IndexOfChar { get { return Line.IndexOfFirstChar + IndexOfCharInLine; } }
public TextLine Line;
public Point Location;
public static FindInfo Empty;
}
}

View File

@ -1,53 +0,0 @@
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public class STTextBoxCaretInfo
{
private int _X;
public int X {
get { return _X; }
internal set {
_X = value;
}
}
private int _Y;
public int Y {
get { return _Y; }
internal set {
_Y = value;
}
}
private int _Width = 1;
public int Width {
get { return _Width; }
set { _Width = value; }
}
public bool Visable;
public int IndexOfLine;
public int IndexOfChar;
public TextLine Line;
public Point Location {
get { return new Point(X, Y); }
}
public bool CopyFromFindInfo(FindInfo fi) {
if (!fi.Find) {
return false;
}
this._X = fi.Location.X;
this._Y = fi.Location.Y;
this.IndexOfChar = fi.IndexOfChar;
this.IndexOfLine = fi.IndexOfLine;
this.Line = fi.Line;
return true;
}
}
}

View File

@ -1,45 +0,0 @@
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public class STTextBoxScrollInfo
{
private int _DisplayTime;
public int DisplayTime {
get { return _DisplayTime; }
set {
if (value < 1) {
throw new ArgumentException("The value must be more than 1");
}
_DisplayTime = value;
}
}
internal int CountDown { get; set; }
public int XValue { get; internal set; }
public int YValue { get; internal set; }
public int MaxXValue { get; set; }
public int MaxYValue { get; set; }
public int XIncrement { get; set; }
public int XOffset { get { return XValue * XIncrement; } }
public int Size { get; internal set; }
public ScrollBarType HoverScrollBar { get; internal set; }
public ScrollBarType DownScrollBar { get; internal set; }
public Rect VThumbRect { get; internal set; }
public Rect HThumbRect { get; internal set; }
public Rect VBackRect { get; internal set; }
public Rect HBackRect { get; internal set; }
public enum ScrollBarType { None, V, H }
public STTextBoxScrollInfo() {
this._DisplayTime = 3;
this.Size = 10;
this.XIncrement = 10;
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public class STTextBoxSelectionInfo
{
public event EventHandler SelectionChanged;
private int _StartIndex;
public int StartIndex {
get { return _StartIndex; }
private set {
if (value == _StartIndex) return;
_StartIndex = value;
//this.OnSelectionChanged(EventArgs.Empty);
}
}
private int _EndIndex;
public int EndIndex {
get { return _EndIndex; }
private set {
if (value == _EndIndex) return;
_EndIndex = value;
//this.OnSelectionChanged(EventArgs.Empty);
}
}
public bool IsBlock { get; set; }
public int AnchorIndex { get; set; }
public int Length { get { return EndIndex - StartIndex; } }
public bool IsEmptySelection { get { return EndIndex == StartIndex; } }
public void SetIndex(int nIndex) { this.SetIndex(nIndex, false); }
public void SetSelection(int nCurrentIndex) { this.SetSelection(nCurrentIndex, false); }
public void SetSelection(int nIndexStart, int nIndexEnd) { this.SetSelection(nIndexStart, nIndexEnd, false); }
public void SetIndex(int nIndex, bool isBlock) {
this.IsBlock = isBlock;
this.AnchorIndex = nIndex;
this.StartIndex = nIndex;
this.EndIndex = nIndex;
this.OnSelectionChanged(EventArgs.Empty);
}
public void SetSelection(int nCurrentIndex, bool isBlock) {
this.IsBlock = isBlock;
if (nCurrentIndex <= this.AnchorIndex) {
this.StartIndex = nCurrentIndex;
this.EndIndex = this.AnchorIndex;
} else {
this.StartIndex = this.AnchorIndex;
this.EndIndex = nCurrentIndex;
}
this.OnSelectionChanged(EventArgs.Empty);
}
public void SetSelection(int nIndexStart, int nIndexEnd, bool isBlock) {
this.IsBlock = isBlock;
this.AnchorIndex = nIndexStart;
if (nIndexStart < nIndexEnd) {
this.StartIndex = nIndexStart;
this.EndIndex = nIndexEnd;
} else {
this.StartIndex = nIndexEnd;
this.EndIndex = nIndexStart;
}
this.OnSelectionChanged(EventArgs.Empty);
}
public void Clear() {
this.StartIndex = 0;
this.EndIndex = 0;
}
protected virtual void OnSelectionChanged(EventArgs e) {
if (this.SelectionChanged != null) {
this.SelectionChanged(this, e);
}
}
}
}

View File

@ -1,131 +0,0 @@
using CPF;
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public struct TextStyle
{
private string EmptyGUID { get; set; }
public string Name;
public Color ForeColor;
public Color BackColor;
public Color UnderLineColor;
public Color StrikeOutColor;
public FontStyles FontStyle;
public bool RejectMix;
public static TextStyle Empty = new TextStyle() {
EmptyGUID = Guid.NewGuid().ToString()
};
public void Mix(TextStyle style) {
//this.ForeColor = _ColorMix(this.ForeColor, style.ForeColor);
//this.BackColor = _ColorMix(this.BackColor, style.BackColor);
//this.UnderLineColor = _ColorMix(this.UnderLineColor, style.UnderLineColor);
//this.StrikeOutColor = _ColorMix(this.StrikeOutColor, style.StrikeOutColor);
//this.FontStyle |= style.FontStyle;
if (this.ForeColor.A == 0) this.ForeColor = style.ForeColor;
if (this.BackColor.A == 0) this.BackColor = style.BackColor;
if (this.UnderLineColor.A == 0) this.UnderLineColor = style.UnderLineColor;
if (this.StrikeOutColor.A == 0) this.StrikeOutColor = style.StrikeOutColor;
this.FontStyle |= style.FontStyle;
}
private static Color _ColorMix(Color a, Color b) {
// T = Foreground, B = Background, F = Mixed
// alphaF = alphaT + alphaB * (1 - alphaT);
// colorF = (colorT * alphaT + colorB * alphaB * (1 - alphaT)) / alphaF;
if (a.A == 255) return a;
float aT = (float)a.A / 255;
float aB = (float)b.A / 255;
float aF = aT + aB * (1 - aT);
float temp = aB * (1 - aT); ;
int nA, nR, nG, nB;
nA = (int)(255 * aF);
nR = (int)((a.R * aT + b.R * temp) / aF);
nG = (int)((a.G * aT + b.G * temp) / aF);
nB = (int)((a.B * aT + b.B * temp) / aF);
return Color.FromArgb(_Range(nA, 0, 255), _Range(nR, 0, 255), _Range(nG, 0, 255), _Range(nB, 0, 255));
}
private static byte _Range(int num, int nMin, int nMax) {
if (num < nMin) {
num = nMin;
} else if (num > nMax) {
num = nMax;
}
return (byte)num;
}
// [override] ==============================================================
public override string ToString() {
return "[" + this.Name + "]{" + this.ForeColor.ConvertToString(null,null) + "," + this.BackColor.ConvertToString(null, null) + "}";
}
public static bool operator ==(TextStyle a, TextStyle b) {
if (a.EmptyGUID != a.EmptyGUID) return false;
if (a.RejectMix != b.RejectMix) return false;
if (a.ForeColor != b.ForeColor) return false;
if (a.BackColor != b.BackColor) return false;
if (a.UnderLineColor != b.UnderLineColor) return false;
if (a.StrikeOutColor != b.StrikeOutColor) return false;
if (a.FontStyle != b.FontStyle) return false;
return true;
}
public static bool operator !=(TextStyle a, TextStyle b) {
return !(a == b);
}
public override bool Equals(object obj) {
return base.Equals(obj);
}
public override int GetHashCode() {
return base.GetHashCode();
}
}
public struct TextStyleRange : IComparable
{
private string EmptyGUID { get; set; }
public int Index;
public int Length;
public TextStyle Style;
public static TextStyleRange Empty = new TextStyleRange() {
EmptyGUID = Guid.NewGuid().ToString()
};
public static bool operator ==(TextStyleRange a, TextStyleRange b) {
if (a.EmptyGUID != b.EmptyGUID) return false;
if (a.Index != b.Index) return false;
if (a.Length != b.Length) return false;
if (a.Style != b.Style) return false;
return true;
}
public static bool operator !=(TextStyleRange a, TextStyleRange b) {
return !(a == b);
}
public override bool Equals(object obj) {
return base.Equals(obj);
}
public override int GetHashCode() {
return base.GetHashCode();
}
public override string ToString() {
return "(" + this.Index + "," + this.Length + ")" + this.Style;
}
public int CompareTo(object obj) {
return this.Index - ((TextStyleRange)obj).Index;
}
}
}

View File

@ -1,373 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CPF.Controls;
using CPF.Drawing;
namespace ST.Library.UI.STTextBox
{
public class STTextBoxSkiaFPRender : ISTTextBoxRender, IDisposable
{
public bool ShowInVisableChar { get; set; }
public Color InVisableCharColor { get; set; }
public int TabSize { get; private set; }
public int SpaceWidth { get; private set; }
public float FontHeight { get; private set; }
public bool IsMonospaced { get; private set; }
private Font m_ft_normal;
private Font m_ft_bold;
private Font m_ft_italic;
private Font m_ft_bold_italic;
private StringFormat m_sf;
private Brush m_brush;//Solid
private Graphics m_g_onpaint;
private Graphics m_g_private;
private float m_italic_width;
private Rect m_rect_temp;
private Rect m_rect_line;
private Dictionary<string, int> m_dic_width_cache;
private Control m_ctrl;
private int m_nCounter;
public STTextBoxSkiaFPRender() {
this.TabSize = 4;
m_dic_width_cache = new Dictionary<string, int>();
m_sf = new StringFormat() {
Alignment = TextAlignment.Center//GenericTypographic
};
//m_sf.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
//m_sf.Alignment = StringAlignment.Center;
//m_sf.LineAlignment = StringAlignment.Center;
m_brush = new SolidColorBrush(Color.Black);//SolidBrush
this.InVisableCharColor = Color.FromArgb(50, Color.Magenta.R, Color.Magenta.G, Color.Magenta.B);
this.ShowInVisableChar = false;
}
public float DPIZoom;
public void BindControl(Control ctrl,View Root) {
DPIZoom = Root.RenderScaling;
if (ctrl == null) {
throw new ArgumentNullException("ctrl");
}
m_ctrl = ctrl;
//m_ctrl.FontChanged += m_ctrl_FontChanged;
//hmbb 字体变更
this.InitData(new Font(m_ctrl.FontFamily, m_ctrl.FontSize, m_ctrl.FontStyle));
}
public void UnbindControl() {
//m_ctrl.FontChanged -= m_ctrl_FontChanged;
}
public void OnBeginPaint(Graphics g) {
//m_g_onpaint = g;
//m_b_onpaint = true;
/*this.XDPIZoom = g.DpiX / 96;
this.YDPIZoom = g.DpiY / 96;
if (this.XDPIZoom < 1) this.XDPIZoom = 1;
if (this.YDPIZoom < 1) this.YDPIZoom = 1;*/
m_g_onpaint = g;
}
public int SetTabSize(int nSize) {
if (nSize < 0) {
throw new ArgumentOutOfRangeException("nSize", "The value must be more than 0");
}
if (nSize > 10) {
throw new ArgumentOutOfRangeException("nSize", "The value must be less than 10");
}
int nRet = this.TabSize;
this.TabSize = nSize;
return nRet;
}
public int GetTabSize() {
return this.TabSize;
}
public int GetTabWidth(int nLeftWidth) {
return (int)Math.Round(this.GetSpaceWidth() * this.GetTabSpaceCount(nLeftWidth, this.TabSize));
}
public int GetFontHeight() { return this.FontHeight; }
public int GetSpaceWidth() { return this.SpaceWidth; }
public float GetTabSpaceCount(int nLeftWidth, int nTabSize) {
if (nTabSize < 0) {
throw new ArgumentOutOfRangeException("nTabSize", "The value must be more than 0");
}
int nSpaceWidth = this.GetSpaceWidth();
if (nTabSize == 1) { //If the TAB size just one SPACE,return the SPACE width;
return nSpaceWidth;
}
int nTabFullWidth = nSpaceWidth * nTabSize;
float nSpaceCount = (nTabFullWidth - (nLeftWidth % nTabFullWidth)) / (float)nSpaceWidth;
return nSpaceCount < 1 ? nSpaceCount + nTabSize : nSpaceCount;
}
public int GetStringWidth(string strText, TextStyle style, int nLeftWidth) {
return this.GetStringWidth(strText, style, nLeftWidth, true);
}
public int GetStringWidth(string strText, TextStyle style, int nLeftWidth, bool bCache) {
if (string.IsNullOrEmpty(strText)/* || m_ft_normal == null*/) {
return 0;
}
Graphics g = this.GetGraphics();
string strKey = this.GetFontFlag(style);
Font ft = this.GetFontFromFlag(strKey);
strKey += ":" + strText;
if (m_dic_width_cache.ContainsKey(strKey)) {
return m_dic_width_cache[strKey];
}
if (strText == "\t") {
return this.GetTabWidth(nLeftWidth);
}
float fWidth = g.MeasureString(strText, ft, 10000, m_sf).Width;
if ((ft.FontStyle & FontStyles.Italic) == FontStyles.Italic) {
fWidth += m_italic_width;
}
int nWidth = (int)Math.Ceiling(fWidth);
if (bCache) {
m_dic_width_cache.Add(strKey, nWidth);
}
return nWidth;
}
public void DrawString(string strText, Font ft, Color color, Rect rect, StringFormat sf) {
m_brush = new SolidColorBrush(color);
this.GetGraphics().DrawString(strText, ft, m_brush, rect, sf);
}
/// <summary>
///
/// </summary>
/// <param name="strText"></param>
/// <param name="style"></param>
/// <param name="rect"></param>
/// <param name="f"></param>
/// <param name="Underline">下划线</param>
public void DrawString(string strText, TextStyle style, Rect rect, TextDecorationLocation Underline = TextDecorationLocation.None) {
Graphics g = this.GetGraphics();
m_rect_line.X = rect.X;
m_rect_line.Width = rect.Width;
if (style.BackColor.A > 0) {
m_brush = new SolidColorBrush(style.BackColor);
g.FillRectangle(m_brush, rect);
}
if (Underline == TextDecorationLocation.Underline && style.UnderLineColor.A > 0) {
m_rect_line.Y = rect.Bottom - m_rect_line.Height;
m_brush = new SolidColorBrush(style.UnderLineColor);
g.FillRectangle(m_brush, m_rect_line);
}
if (style.ForeColor.A > 0) {
m_brush = new SolidColorBrush(style.ForeColor);
switch (strText[0]) {
case ' ':
if (this.ShowInVisableChar) this.OnDrawSpaceChar(rect);
return;
case '\t':
if (this.ShowInVisableChar) this.OnDrawTabChar(rect);
return;
case '\r':
case '\n':
if (this.ShowInVisableChar) this.OnDrawNewLineChar(rect);
return;
default:
g.DrawString(strText, this.GetFontFromFlag(this.GetFontFlag(style)), m_brush, rect, m_sf);
break;
}
}
if (Underline == TextDecorationLocation.Strikethrough && style.StrikeOutColor.A > 0) {
m_rect_line.Y = rect.Y + rect.Height / 2;
m_brush = new SolidColorBrush(style.StrikeOutColor);
g.FillRectangle(m_brush, m_rect_line);
}
}
public void DrawImage(Image image, Rect rect) {
this.GetGraphics().DrawImage(image, rect);
}
public void FillRectangle(Color backColor, Rect rect) {
m_brush = new SolidColorBrush(backColor) ;
this.GetGraphics().FillRectangle(m_brush, rect);
}
public void FillRectangle(Color backColor, float nX, float nY, float nWidth, float nHeight) {
m_brush = new SolidColorBrush(backColor);
this.GetGraphics().FillRectangle(m_brush, nX, nY, (float)nWidth, (float)nHeight);
}
//hmbb 下面这两个我也不知道干嘛的
public void SetClip(Rect rect) {
//this.GetGraphics().SetClip(rect);
}
public void ResetClip() {
//this.GetGraphics().ResetClip();
}
// [protected] ==========================================
protected virtual void OnDrawNewLineChar(Rect rect) {
Graphics g = this.GetGraphics();
m_brush = new SolidColorBrush(this.InVisableCharColor);
m_rect_temp.X = rect.X + (int)Math.Round(this.DPIZoom);
m_rect_temp.Y = rect.Y + rect.Height / 2 - (int)Math.Round(this.DPIZoom);
m_rect_temp.Height = (int)Math.Round(this.DPIZoom * 3);
m_rect_temp.Width = (int)Math.Round(this.DPIZoom);
g.FillRectangle(m_brush, m_rect_temp); // draw -> |
m_rect_temp.X += (int)Math.Round(this.DPIZoom);
m_rect_temp.Y += (int)Math.Round(this.DPIZoom);
m_rect_temp.Height = (int)Math.Round(this.DPIZoom);
m_rect_temp.Width = rect.Width - (int)Math.Round(this.DPIZoom * 4);
g.FillRectangle(m_brush, m_rect_temp); // draw -> -
m_rect_temp.X = m_rect_temp.Right;
m_rect_temp.Width = (int)Math.Round(this.DPIZoom);
m_rect_temp.Height = (int)Math.Round(this.DPIZoom * 5);
m_rect_temp.Y -= (int)Math.Round(this.DPIZoom * 4);
g.FillRectangle(m_brush, m_rect_temp); // draw -> |
}
protected virtual void OnDrawTabChar(Rect rect) {
Graphics g = this.GetGraphics();
m_brush = new SolidColorBrush(this.InVisableCharColor);
m_rect_temp.Height = (int)Math.Round(this.DPIZoom * 3);
m_rect_temp.Width = (int)Math.Round(this.DPIZoom);// *2;
m_rect_temp.Y = rect.Y + rect.Height / 2 - (int)Math.Round(this.DPIZoom);
m_rect_temp.X = rect.X + (int)Math.Round(this.DPIZoom);
g.FillRectangle(m_brush, m_rect_temp);
m_rect_temp.X = rect.Right - (int)Math.Round(this.DPIZoom * 2);
g.FillRectangle(m_brush, m_rect_temp);
m_rect_temp.Y += (int)Math.Round(this.DPIZoom);
m_rect_temp.Height = (int)Math.Round(this.DPIZoom);
m_rect_temp.X = rect.X + (int)Math.Round(this.DPIZoom * 2);
m_rect_temp.Width = rect.Width - (int)Math.Round(this.DPIZoom * 4);
g.FillRectangle(m_brush, m_rect_temp);
}
protected virtual void OnDrawSpaceChar(Rect rect) {
Graphics g = this.GetGraphics();
m_brush = new SolidColorBrush(this.InVisableCharColor);
m_rect_temp.Height = (int)Math.Round(this.DPIZoom);
m_rect_temp.Width = rect.Width - (int)Math.Round(this.DPIZoom * 2);// *2;
m_rect_temp.X = rect.X + (int)Math.Round(this.DPIZoom);
m_rect_temp.Y = rect.Bottom - (int)Math.Round(this.DPIZoom * 2);
g.FillRectangle(m_brush, m_rect_temp);
m_rect_temp.Width = m_rect_temp.Height;
m_rect_temp.X = rect.X + m_rect_temp.Width;
m_rect_temp.Y -= m_rect_temp.Height;
g.FillRectangle(m_brush, m_rect_temp);
m_rect_temp.X = rect.Right - (int)Math.Round(this.DPIZoom * 2);
g.FillRectangle(m_brush, m_rect_temp);
}
// [private] ============================================
private void m_ctrl_FontChanged(object sender, EventArgs e) {
this.InitData(new Font(m_ctrl.FontFamily, m_ctrl.FontSize, m_ctrl.FontStyle));
}
private void InitData(Font ft) {
/*if (m_ft_normal == ft) {
return;
}*/
//this.BeginPaint();
m_rect_line.Height = (int)Math.Round(this.DPIZoom * 1);
if (m_rect_line.Height == 0) m_rect_line.Height = 1;
m_ft_normal = ft;
if (!m_ft_bold.IsNull) m_ft_bold.Dispose();
m_ft_bold = new Font(ft.FontFamily, ft.FontSize, FontStyles.Bold);
if (!m_ft_italic.IsNull) m_ft_italic.Dispose();
m_ft_italic = new Font(ft.FontFamily, ft.FontSize, FontStyles.Italic);
if (!m_ft_bold_italic.IsNull) m_ft_bold_italic.Dispose();
m_ft_bold_italic = new Font(ft.FontFamily,ft.FontSize, FontStyles.Bold | FontStyles.Italic);
this.FontHeight = ft.FontSize;////hmbb
m_dic_width_cache.Clear();
//SPACE are used to calculate TAB width.
int nWidth = this.GetStringWidth(" ", TextStyle.Empty, 0);
m_dic_width_cache.Add(" ", nWidth);
m_dic_width_cache.Add("\r", nWidth);
m_dic_width_cache.Add("\n", nWidth);
m_dic_width_cache.Add("\r\n", nWidth);
this.SpaceWidth = nWidth;
this.IsMonospaced = this.GetStringWidth("i", TextStyle.Empty, 0) == this.GetStringWidth("W", TextStyle.Empty, 0);
if (!this.IsMonospaced) {
m_italic_width = (float)(this.FontHeight * Math.Tan(12 * Math.PI / 180));
} else {
m_italic_width = 0;
}
}
private Graphics GetGraphics() {
if (m_g_onpaint != null) return m_g_onpaint;
if (m_g_private != null) return m_g_private;
throw new InvalidOperationException("The Graphics is null, please call BeginPaint() to init it.");
}
private string GetFontFlag(TextStyle style) {
string strKey = "N";
if ((style.FontStyle & FontStyles.Bold) == FontStyles.Bold) {
strKey += "B";
}
if ((style.FontStyle & FontStyles.Italic) == FontStyles.Italic) {
strKey += "I";
}
return strKey;
}
private Font GetFontFromFlag(string strFlag) {
switch (strFlag) {
case "NBI":
return m_ft_bold_italic;
case "NB":
return m_ft_bold;
case "NI":
return m_ft_italic;
}
return m_ft_normal;
}
// [interface] ==========================================
public void Dispose() {
//if (m_g_private != null) m_g_private.Dispose();
if (!m_ft_bold.IsNull) m_ft_bold.Dispose();
if (!m_ft_italic.IsNull) m_ft_italic.Dispose();
if (!m_ft_bold_italic.IsNull) m_ft_bold_italic.Dispose();
if (m_brush != null) m_brush.Dispose();
//if (m_sf != null) m_sf.Dispose();
if (m_dic_width_cache != null) m_dic_width_cache.Clear();
}
public void BindControl(Control ctrl)
{
//throw new NotImplementedException();
}
public void OnEndPaint(Graphics g)
{
//throw new NotImplementedException();
}
public void BeginPaint()
{
//throw new NotImplementedException();
}
public void EndPaint()
{
//throw new NotImplementedException();
}
}
}

View File

@ -1,973 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Text.RegularExpressions;
namespace ST.Library.UI.STTextBox
{
public class CSharpStyleMonitor : TextStyleMonitor
{
public TextStyle DefaultStyle { get; set; }
public TextStyle CommentStyle { get; set; }
public TextStyle DocCommentStyle { get; set; }
public TextStyle KeyWordStyle { get; set; }
public TextStyle StringStyle { get; set; }
public TextStyle OperatorStyle { get; set; }
public TextStyle DelimiterStyle { get; set; }
public TextStyle NumberStyle { get; set; }
public TextStyle BuiltInTypeStyle { get; set; }
public TextStyle PropertyStyle { get; set; }
public TextStyle CustomTypeStyle { get; set; }
public TextStyle FunctionDeclStyle { get; set; }
public TextStyle FunctionCallStyle { get; set; }
public TextStyle FunctionBuiltInStyle { get; set; }
private enum SymbolType
{
Comment,
DocComment,
KeyWord,
String,
Operator,
Delimiter,
Number,
BuiltInType,
CustomType,
Property,
FunctionDecl,
FunctionCall,
FunctionBuiltIn,
None
}
private class Symbol : IComparable
{
public SymbolType Type;
public string Value;
public int Index;
public int Length;
public Symbol(SymbolType type, string value, int nIndex, int nLen) {
this.Type = type;
this.Value = value;
this.Index = nIndex;
this.Length = nLen;
}
public override string ToString() {
return "[" + this.Type + "] - (" + this.Index + "," + this.Length + ") - " + this.Value;
}
public int CompareTo(object obj) {
return this.Index - ((Symbol)obj).Index;
}
}
private static string m_str_type = "void,var,object,dynamic,long,ulong,int,uint,short,ushort,byte,sbyte,float,double,decimal,bool,char,string,params";
private static string m_str_modifier = "private,public,internal,protected,partial,sealed,abstract,static,extern,virtual,override,fixed,unsafe,readonly,const";
private static string m_str_object = "event,enum,struct,class,new";
private static string m_str_flow = "for,foreach,if,else,do,while,switch,case,default,break,continue,goto,return";
private static string m_str_value = "null,true,false";
private static string m_str_other = "try,catch,finally,throw,using,namespace,this,base,in,is,as,get,set,ref,out,value,stackalloc,unchecked,lock";
private static string m_str_func = "sizeof,typeof,nameof";
private static string m_str_linq = "let,select,from,group,into,where,join,orderby,ascending,descending";
private static string m_str_operator = "+-*/<>!=&|~^?:";
private static string m_str_delimiter = "[](){},;";
private static Regex m_reg_w = new Regex(@"\w+");
private static Regex m_reg_W = new Regex(@"\W");
private static HashSet<string> m_hs_all_key;
private static HashSet<string> m_hs_type;
private static HashSet<string> m_hs_object;
private static HashSet<string> m_hs_modifier;
private static HashSet<string> m_hs_function;
private static HashSet<string> m_hs_operator;
private static HashSet<string> m_hs_delimiter;
private List<Symbol> m_lst_smb;
private List<TextStyleRange> m_lst_range;
static CSharpStyleMonitor() {
m_hs_all_key = new HashSet<string>();
string[] strs = { m_str_type, m_str_modifier, m_str_object, m_str_flow, m_str_value, m_str_other, m_str_func, m_str_linq };
foreach (var v in strs) {
foreach (var s in v.Split(',')) {
m_hs_all_key.Add(s);
}
}
m_hs_type = new HashSet<string>();
foreach (var v in m_str_type.Split(',')) {
m_hs_type.Add(v);
}
m_hs_modifier = new HashSet<string>();
foreach (var v in m_str_modifier.Split(',')) {
m_hs_modifier.Add(v);
}
m_hs_object = new HashSet<string>();
foreach (var v in m_str_object.Split(',')) {
m_hs_object.Add(v);
}
m_hs_function = new HashSet<string>();
foreach (var v in m_str_func.Split(',')) {
m_hs_function.Add(v);
}
m_hs_operator = new HashSet<string>();
foreach (var v in m_str_operator) {
m_hs_operator.Add(v.ToString());
}
m_hs_delimiter = new HashSet<string>();
foreach (var v in m_str_delimiter) {
m_hs_delimiter.Add(v.ToString());
}
}
public CSharpStyleMonitor() {
m_lst_smb = new List<Symbol>();
m_lst_range = new List<TextStyleRange>();
this.DefaultStyle = new TextStyle() { ForeColor = Color.Black };
this.CommentStyle = new TextStyle() { ForeColor = Color.Green };
this.DocCommentStyle = new TextStyle() { ForeColor = Color.Gray };
this.KeyWordStyle = new TextStyle() { ForeColor = Color.Blue };
this.StringStyle = new TextStyle() { ForeColor = Color.Brown };
this.OperatorStyle = new TextStyle() { ForeColor = Color.DarkMagenta };
this.DelimiterStyle = new TextStyle() { ForeColor = Color.Gray };
this.NumberStyle = new TextStyle() { ForeColor = Color.Orange };
this.BuiltInTypeStyle = new TextStyle() { ForeColor = Color.CornflowerBlue };
this.PropertyStyle = new TextStyle() { ForeColor = Color.SlateGray };
this.CustomTypeStyle = new TextStyle() { ForeColor = Color.DarkCyan };
this.FunctionDeclStyle = new TextStyle() { ForeColor = Color.DarkViolet };
this.FunctionCallStyle = new TextStyle() { ForeColor = Color.PaleVioletRed };
this.FunctionBuiltInStyle = new TextStyle() { ForeColor = Color.CornflowerBlue };
}
public override void Init(string strText) {
m_lst_smb.Clear();
int nIndex = 0;
//bool bFlag = false;
string strTemp = string.Empty;
StringBuilder sb = new StringBuilder();
List<Symbol> lst = new List<Symbol>();
for (int i = 0; i < strText.Length; i++) {
char ch = strText[i];
//====== symbol ======
//bFlag = (ch >= '0' && ch <= '9');
//bFlag |= (ch >= 'a' && ch <= 'z');
//bFlag |= (ch >= 'A' && ch <= 'Z');
//bFlag |= (ch == '_');
if (this.CheckIsIdentifierChar(ch)) {
sb.Append(ch);
continue;
}
//====================
if (sb.Length != 0) {
lst.Add(new Symbol(SymbolType.None, sb.ToString(), i - sb.Length, sb.Length));
sb.Remove(0, sb.Length);
}
switch (ch) {
case ' ':
case '\t':
case '\r':
case '\n':
continue;
}
if (ch == '/' && i + 1 < strText.Length) {
switch (strText[i + 1]) {
case '*':
strTemp = this.GetComment1(strText, i);
m_lst_smb.Add(new Symbol(SymbolType.Comment, strTemp, i, strTemp.Length));
i += strTemp.Length;
nIndex = i;
continue;
case '/':
strTemp = this.GetComment2(strText, i);
nIndex = i;
if (strTemp.StartsWith("///")) {
Regex reg = new Regex(@"<.*?>");
foreach (Match m in reg.Matches(strTemp)) {
if (nIndex < i + m.Index) {
m_lst_smb.Add(new Symbol(SymbolType.Comment, strText.Substring(nIndex, i + m.Index - nIndex), nIndex, i + m.Index - nIndex));
nIndex = i + m.Index;
}
m_lst_smb.Add(new Symbol(SymbolType.DocComment, m.Value, i + m.Index, m.Length));
nIndex = i + m.Index + m.Length;
}
if (nIndex < i + strTemp.Length) {
m_lst_smb.Add(new Symbol(SymbolType.Comment, strText.Substring(nIndex - i, strTemp.Length - nIndex + i), nIndex, strTemp.Length - nIndex + i));
}
} else {
m_lst_smb.Add(new Symbol(SymbolType.Comment, strTemp, i, strTemp.Length));
}
i += strTemp.Length;
nIndex = i;
continue;
}
}
if (ch == '@' && i + 1 < strText.Length && strText[i + 1] == '"') {
string strString = this.GetString1(strText, i);
lst.Add(new Symbol(SymbolType.String, strString, i, strString.Length));
i += strString.Length - 1;
nIndex = i;
continue;
}
if (ch == '"' || ch == '\'') {
string strString = ch == '\'' ? this.GetChar(strText, i) : this.GetString2(strText, i);
lst.Add(new Symbol(SymbolType.String, strString, i, strString.Length));
i += strString.Length - 1;
nIndex = i;
continue;
}
lst.Add(new Symbol(SymbolType.None, ch.ToString(), i, 1));
}
if (sb.Length != 0) {
lst.Add(new Symbol(SymbolType.None, sb.ToString(), strText.Length - sb.Length, sb.Length));
}
this.ProcessSymbol(lst);
m_lst_smb.AddRange(lst);
m_lst_smb.Sort();
var aa = this.Clear(m_lst_smb);
//m_lst_smb.AddRange(aa);
//m_lst_smb.Sort();
m_lst_range = this.SymbolToRange(aa);
}
private List<Symbol> Clear(List<Symbol> lst) {
List<Symbol> ret = new List<Symbol>();
if (lst == null || lst.Count == 0) {
return ret;
}
Symbol last = lst[0];
if (last.Type != SymbolType.None) {
ret.Add(last);
}
for (int i = 1; i < lst.Count; i++) {
if (m_hs_operator.Contains(lst[i].Value)) {
lst[i].Type = SymbolType.Operator;
}
if (char.IsNumber(lst[i].Value[0])) {
lst[i].Type = SymbolType.Number;
}
if (m_hs_delimiter.Contains(lst[i].Value)) {
lst[i].Type = SymbolType.Delimiter;
}
switch (lst[i].Value) {
case "<": // like -> List<int>
case ">":
if (lst[i - 1].Type == SymbolType.BuiltInType || lst[i - 1].Type == SymbolType.CustomType) {
lst[i].Type = SymbolType.None;
}
break;
}
if (lst[i].Value == "." && i + 1 < lst.Count) {
lst[i].Type = lst[i + 1].Type;
}
if (lst[i].Type == SymbolType.None) {
last = lst[i];
continue;
}
if (last.Type == lst[i].Type) {
last.Length = lst[i].Index + lst[i].Length - last.Index;
continue;
}
last = lst[i];
ret.Add(lst[i]);
}
return ret;
}
private List<TextStyleRange> SymbolToRange(List<Symbol> lst) {
List<TextStyleRange> lst_ret = new List<TextStyleRange>();
foreach (var v in lst) {
lst_ret.Add(new TextStyleRange() {
Index = v.Index,
Length = v.Length,
Style = this.GetColorFromSymbolType(v.Type)
});
}
return lst_ret;
}
private void ProcessSymbol(List<Symbol> lst) {
for (int i = 0; i < lst.Count; i++) {
//if (m_hs_operators.Contains(lst[i].Value)) {
// lst[i].Type = SymbolType.Operator;
//}
//if (char.IsNumber(lst[i].Value[0])) {
// lst[i].Type = SymbolType.Number;
//}
if (lst[i].Value == "." && i + 1 < lst.Count && this.CheckIsIdentifier(lst[i + 1].Value)) {
lst[i + 1].Type = SymbolType.Property;
}
if (m_hs_modifier.Contains(lst[i].Value)) {
lst[i].Type = SymbolType.KeyWord;
if (!this.CheckIsDeclare(lst, i)) {
continue;
}
i += this.CheckDeclare(lst, i);
continue;
}
if (m_hs_object.Contains(lst[i].Value)) {
lst[i].Type = SymbolType.KeyWord;
i += this.CheckObject(lst, i);
continue;
}
if (m_hs_all_key.Contains(lst[i].Value)) {
lst[i].Type = m_hs_type.Contains(lst[i].Value) ? SymbolType.BuiltInType : SymbolType.KeyWord;
if (m_hs_function.Contains(lst[i].Value)) lst[i].Type = SymbolType.FunctionBuiltIn;
switch (lst[i].Value) {
case "sizeof":
case "typeof":
case "foreach":
case "catch":
if (i + 2 < lst.Count && this.CheckIsIdentifier(lst[i + 2].Value)) {
i += this.CheckDataType(lst, i + 2);
continue;
}
i += 2;
break;
}
continue;
}
switch (lst[i].Value) { // A new sentence after these.
case ";":
case "{":
case "}":
case "]":
if (i + 1 >= lst.Count) break;
if (lst[i + 1].Value == "[") {
i += this.CheckAttribute(lst, i + 1);
break;
}
if (!this.CheckIsIdentifier(lst[i + 1].Value)) break;
// If can not match a key word, maybe is a custom type (such as: {CustomType a = null;})
if (m_hs_type.Contains(lst[i + 1].Value) && this.CheckIsDeclare(lst, i + 1)) {
i += this.CheckDataType(lst, i + 1) + 1;
}
break;
case "=":
this.ProcessEqual(lst, i);
break;
case "[":
if (i - 1 < 0) break;
switch (lst[i - 1].Value) {
case ";":
case "{":
case "}":
case "]":
i += this.CheckAttribute(lst, i) - 1;
break;
}
break;
case "(":
i += this.CheckFunction(lst, i);
break;
}
}
}
private int CheckObject(List<Symbol> lst, int nIndex) {
// after [class enum struct new]
for (int i = nIndex + 1; i < lst.Count; i++) {
i = this.GetNextSymbolIndex(lst, i);
switch (lst[i].Value) {
case ":": // Extened
case "<": // Generic
case ",":
case ">":
continue;
default:
if (!this.CheckIsIdentifier(lst[i].Value)) {
return i - nIndex;
}
break;
}
lst[i].Type = m_hs_type.Contains(lst[i].Value) ? SymbolType.BuiltInType : SymbolType.CustomType;
}
return lst.Count - nIndex;
}
private int CheckDeclare(List<Symbol> lst, int nIndex) {
// Rule: MODIFIER? DATA_TYPE NAME [( or <]
int nTemp = nIndex;
while (nTemp < lst.Count && m_hs_modifier.Contains(lst[nTemp].Value)) {
lst[nTemp++].Type = SymbolType.KeyWord; //Igonre the modifier
}
if (nTemp >= lst.Count) return nTemp - nIndex;
if (!this.CheckIsIdentifier(lst[nTemp].Value)) {
return nTemp - nIndex;
}
if (m_hs_object.Contains(lst[nTemp].Value)) {
// if is [class struce enum .. ], so it's a declaration of an object
lst[nTemp].Type = SymbolType.KeyWord;
nTemp += this.CheckObject(lst, nTemp);
return nTemp - nIndex;
}
// now lst[nTemp] is a DATA_TYPE
if (nTemp + 1 >= lst.Count || lst[nTemp + 1].Value != "(") { // if is end or next char is not '('
// if lst[nTemp + 1] is "(". maybe like this "MODIFIER? DATA_TYPE("
// maybe is a Constructor like this "public ClassName("
nTemp += this.CheckDataType(lst, nTemp);
}
if (nTemp >= lst.Count) return nTemp - nIndex;
// now lst[nTemp] is NAME
if (lst[nTemp].Value == "operator") { // Overloaded operator functions are special. So deal with it independently.
lst[nTemp].Type = SymbolType.KeyWord;
if (nTemp + 2 < lst.Count && lst[++nTemp + 1].Value != "(") {
nTemp++;
}
if (lst[nTemp + 1].Value != "(") {
return nTemp - nIndex;
}
}
if (++nTemp >= lst.Count) return nTemp - nIndex;
// now -> "MODIFIER? DATA_TYPE NAME<". maybe is a generic function
if (lst[nTemp].Value == "<") {
int n = nTemp;
nTemp += this.CheckDataType(lst, nTemp - 1) - 1;
lst[n - 1].Type = SymbolType.FunctionDecl;
if (nTemp >= lst.Count) return nTemp - nIndex;
}
// now -> "MODIFIER? DATA_TYPE NAME(". so it's a function
if (lst[nTemp].Value == "(") {
if (this.CheckIsIdentifier(lst[nTemp - 1].Value)) {
lst[nTemp - 1].Type = SymbolType.FunctionDecl;
}
nTemp += this.CheckFunctionParam(lst, nTemp) - 1;
}
// The other case is the declaration of a variable.
return nTemp - nIndex;
}
private int CheckFunction(List<Symbol> lst, int nIndex) {
// lst[nIndex] is "("
if (nIndex - 1 >= 0 && lst[nIndex - 1].Type != SymbolType.None && lst[nIndex - 1].Type != SymbolType.Property) {
return 0;
}
// first check if is convert like -> (xxx)xx or (xxx<xxx.XXX,xxx>[])xxx
for (int i = nIndex + 1; i < lst.Count; i++) {
switch (lst[i].Value) {
case ".": // xxx.xxx
case "<": // generic
case ",":
case ">":
case "[": // array
case "]":
continue;
case ")":
if (i + 1 < lst.Count && this.CheckIsIdentifier(lst[i + 1].Value)) {
return this.CheckDataType(lst, nIndex + 1);
}
break;
default:
if (!this.CheckIsIdentifier(lst[i].Value)) {
break;
}
continue;
}
break;
}
// Note: On the left of "(" can be a function or a constructor of an object
// But if is "new xxx(" will not run this function. will run CheckObject()
int nTemp = nIndex - 1;
if (nTemp < 0) return 0;
// if last char is '>', maybe is a generic function
if (lst[nTemp].Value == ">") { // maybe is a generic, find the '<'
nTemp -= this.GetGenericLength(lst, nTemp);
this.CheckDataType(lst, nTemp);
}
if (nTemp < 0) return 0;
// new -> list[nTemp] is NAME
if (!this.CheckIsIdentifier(lst[nTemp].Value)) return 0;
if (nTemp - 1 >= 0 && this.CheckIsBoundary(lst[nTemp - 1].Value[0])) {
lst[nTemp].Type = SymbolType.FunctionCall;
} else {
lst[nTemp].Type = SymbolType.FunctionDecl;
}
//this.CheckFunctionName(lst, nTemp);
//if (lst[nTemp].Value == "catch") {
// return this.CheckFunctionParam(lst, nTemp + 1);
//}
if (--nTemp < 0) return 0;
// now -> lst[nTemp] maybe is DATA_TYPE
if (lst[nTemp].Value == "]") { // maybe is a array, find the '['
nTemp -= this.GetArrayLength(lst, nTemp);
}
if (nTemp < 0) return 0;
if (lst[nTemp].Value == ">") { // maybe is a generic, find the '<'
nTemp -= this.GetGenericLength(lst, nTemp);
this.CheckDataType(lst, nTemp);
}
if (nTemp < 0) return 0;
// now -> lst[nTemp] maybe is DATA_TYPE;
if (this.CheckIsBoundary(lst[nTemp].Value[0])) { // It's a function call like ".XXX(" or ";XXX("
return 0;
}
// other cases, it's a function declaration
if (lst[nTemp].Type == SymbolType.None) { // if none ,so it's not generic
lst[nTemp].Type = m_hs_type.Contains(lst[nTemp].Value) ? SymbolType.BuiltInType : SymbolType.CustomType;
}
return this.CheckFunctionParam(lst, nIndex) - 1;
}
private int CheckFunctionParam(List<Symbol> lst, int nIndex) {
// lst[nIndex] is '(' or '(' right char
int nTemp = nIndex;
for (int i = nIndex; i < lst.Count; i++) {
nTemp = nIndex;
switch (lst[i].Value) {
case "(":
case ",":
continue;
case "[":
i += this.CheckAttribute(lst, i) - 1;
continue;
case ")":
return i - nIndex + 1;
case "params":
lst[i].Type = SymbolType.KeyWord;
continue;
default:
if (!this.CheckIsIdentifier(lst[i].Value)) {
nTemp = i;
break;
}
i += this.CheckDataType(lst, i);
if (i < lst.Count && !this.CheckIsIdentifier(lst[i].Value)) {
nTemp = i;
break;
}
continue;
}
break;
}
return nTemp - nIndex + 1;
}
private int CheckAttribute(List<Symbol> lst, int nIndex) {
// Attribute -> [attr(value)] or [attr(value),attr(vule)]
// lst[nIndex] is '[' and left char is [';', '{', '}', ']' ]
if (nIndex + 2 >= lst.Count) {
return 1;
}
if (lst[nIndex + 1].Value == "]") { // maybe just a array like -> new int[][]();
return 2;
}
if (lst[nIndex + 2].Value == "]") { // maybe just a array like -> new int[2][2]();
return 3; // Note: new int[][GetLength(x)](); will run this
}
int nTemp = this.GetNextSymbolIndex(lst, nIndex + 1);
lst[nTemp].Type = SymbolType.CustomType;
for (int i = nIndex + 2; i < lst.Count; i++) {
if (lst[i].Value == "." && i + 1 < lst.Count && this.CheckIsIdentifier(lst[i + 1].Value)) {
lst[i + 1].Type = SymbolType.Property;
}
if ((lst[i].Value == ")" || lst[i].Value == ",") && i - 3 >= 0) {
if (lst[i - 2].Value == ".") { // like this [attr(XXX.xx, xx.XXX.xx)]
lst[i - 3].Type = SymbolType.CustomType; // XXX will be set as custom type
}
}
if (lst[i].Value == "(" && lst[i - 1].Type == SymbolType.None) {
lst[i - 1].Type = SymbolType.CustomType;
}
if (m_hs_all_key.Contains(lst[i].Value) && lst[i - 1].Value != ".") {
lst[i].Type = SymbolType.KeyWord;
switch (lst[i].Value) {
case "sizeof":
case "typeof":
if (i + 2 < lst.Count && lst[i + 1].Value == "(" && this.CheckIsIdentifier(lst[i + 2].Value)) {
lst[i + 2].Type = m_hs_type.Contains(lst[i + 2].Value) ? SymbolType.BuiltInType : SymbolType.CustomType;
}
i += 2;
break;
}
}
if (lst[i].Value == "]") {
return i - nIndex + 1;
}
}
return 1;
}
private int CheckDataType(List<Symbol> lst, int nIndex) {
// Note: This function will not check if the lst[nIndex] is valid data type
// The current function treats lst[nIndex] directly as a data type.
int nTemp = this.GetNextSymbolIndex(lst, nIndex);
// Rule: DATA_TYPE NAME
//if (nTemp + 1 < lst.Count) {
if (m_hs_object.Contains(lst[nTemp].Value)) {
lst[nTemp].Type = SymbolType.KeyWord;
nTemp += this.CheckObject(lst, nTemp);
return nTemp - nIndex;
} else if (m_hs_type.Contains(lst[nTemp].Value)) {
lst[nTemp].Type = SymbolType.BuiltInType;
} else { // -> like "public int XXX{get; private set;}"
lst[nTemp].Type = m_hs_all_key.Contains(lst[nTemp].Value) ? SymbolType.KeyWord : SymbolType.CustomType;
}
if (nTemp + 1 < lst.Count && lst[nTemp + 1].Value == "<") { // so it's generic type like -> "xxx<xx,xx>"
for (int j = nTemp + 2; j < lst.Count; j++) {
switch (lst[j].Value) {
case ".":
case ",":
continue;
case ">":
nTemp = j;
break;
default:
j += this.CheckDataType(lst, j) - 1;
continue;
}
break;
}
}
// so it's array like -> "xxx[]"
if (nTemp + 1 < lst.Count && lst[nTemp + 1].Value == "[") {
nTemp += this.GetArrayLength(lst, nTemp + 1);
}
//}
return nTemp - nIndex + 1;
}
private void ProcessEqual(List<Symbol> lst, int nIndex) {
if (lst[nIndex].Value != "=") {
return;
}
if (nIndex + 1 < lst.Count && lst[nIndex + 1].Value == "=") { // == return
return;
}
if (--nIndex < 0) return;
// now lst[nIndex] is variable
if (this.CheckIsIdentifier(lst[nIndex].Value)) { // it's a variable -> "xxx ="
//lst[nIndex].Type = SymbolType.None;
} else {
return;
}
if (--nIndex < 0) return;
// now lst[nIndex] is data type
if (this.CheckIsIdentifier(lst[nIndex].Value)) {
lst[nIndex].Type = m_hs_type.Contains(lst[nIndex].Value) ? SymbolType.BuiltInType : SymbolType.CustomType;
return;
}
if (lst[nIndex].Value == "]") { // maybe is array -> "] xxx =" -> "xxx[] xxx ="
nIndex -= this.GetArrayLength(lst, nIndex);
}
if (lst[nIndex].Value == ">") {
nIndex -= this.GetGenericLength(lst, nIndex);
this.CheckDataType(lst, nIndex);
}
}
private bool CheckIsIdentifier(string strText) {
return m_reg_w.Match(strText).Value.Length == strText.Length;
//char ch = strText[0];
//bool bFlag = ch == '_';
//bFlag |= ch >= 'a' && ch <= 'z';
//bFlag |= ch >= 'A' && ch <= 'Z';
//return bFlag;
}
private bool CheckIsIdentifierChar(char ch) {
return !m_reg_W.IsMatch(ch.ToString());
//if (this.CheckIsBoundary(ch)) return false;
//if (ch < '0') return false;
//if (ch > 'z' && ch < 256) return false;
//return true;
//switch (ch) {
// case ' ':
// case '\t':
// case '\r':
// case '\n':
// case
//}
}
private bool CheckIsBoundary(char ch) {
switch (ch) {
case '.':
case ';':
case ',':
case '!':
case '=':
case '(':
case ')':
case '<':
case '>':
case '{':
case '}':
case '[':
case ']':
case '+':
case '-':
case '*':
case '/':
case '\\':
case '&':
case '|':
case '^':
case '~':
case '%':
case '?':
case ':':
return true;
}
return false;
}
private bool CheckIsDeclare(List<Symbol> lst, int nIndex) {
// Rule: MODIFIER? DATA_TYPE NAME
int nTemp = nIndex;
while (nTemp < lst.Count && m_hs_modifier.Contains(lst[nTemp].Value)) {
nTemp++; //Igonre the modifier
}
nTemp = this.GetNextSymbolIndex(lst, nIndex);
// now lst[nTemp] is DATA_TYPE
if (!this.CheckIsIdentifier(lst[nTemp].Value)) {
return false;
}
if (nTemp + 1 < lst.Count && lst[nTemp + 1].Value == "<") { // generic
int nLen = this.GetGenericLength(lst, nTemp + 1);
if (nLen == 0) {
return false;
}
nTemp += nLen;
}
if (nTemp + 1 < lst.Count && lst[nTemp + 1].Value == "[") { // array
int nLen = this.GetArrayLength(lst, nTemp + 1);
if (nLen == 0) {
return false;
}
nTemp += nLen;
}
if (nTemp + 1 < lst.Count) {
return this.CheckIsIdentifier(lst[nTemp + 1].Value); // check the NAME
}
return true;
}
private int GetNextSymbolIndex(List<Symbol> lst, int nIndex) {
// "xxx.xxx.xxx.xxx.XXX"
// will return XXX's index
int nTemp = nIndex;
while (nIndex + 1 < lst.Count && lst[nIndex + 1].Value == ".") {
if (nIndex + 2 < lst.Count && this.CheckIsIdentifier(lst[nIndex + 2].Value)) {
lst[nIndex + 2].Type = SymbolType.Property;
}
nIndex += 2;
}
if (nIndex >= lst.Count) nIndex -= 2;
if (nIndex < 0) nIndex = 0;
return nIndex;
}
private int GetGenericLength(List<Symbol> lst, int nIndex) {
// such as: XXX<xx,xx> or XXX<xxx,XXX<xxx.xxx.XXX>>
int nCounter = 0;
if (lst[nIndex].Value == "<") {
for (int i = nIndex; i < lst.Count; i++) {
switch (lst[i].Value) {
case ".":
case ",":
continue;
case "<":
nCounter++;
continue;
case ">":
if (--nCounter == 0) {
return i - nIndex + 1;
}
continue;
default:
if (!this.CheckIsIdentifier(lst[i].Value)) {
return 0;
}
continue;
}
}
} else if (lst[nIndex].Value == ">") {
for (int i = nIndex; i >= 0; i--) {
switch (lst[i].Value) {
case ".":
case ",":
continue;
case ">":
nCounter++;
continue;
case "<":
if (--nCounter == 0) {
return nIndex - i + 1;
}
continue;
default:
if (!this.CheckIsIdentifier(lst[i].Value)) {
return 0;
}
continue;
}
}
}
return 0;
}
private int GetArrayLength(List<Symbol> lst, int nIndex) {
// such as: [] or [,] or [,,,] or [][]
if (lst[nIndex].Value == "[") {
for (int i = nIndex; i < lst.Count; i++) {
switch (lst[i].Value) {
case ",":
continue;
case "]":
if (i + 1 < lst.Count && lst[i + 1].Value == "[") {
continue;
}
return i - nIndex + 1;
}
}
} else if (lst[nIndex].Value == "]") {
for (int i = nIndex; i >= 0; i--) {
switch (lst[i].Value) {
case ",":
continue;
case "[":
if (i - 1 >= 0 && lst[i - 1].Value == "]") {
continue;
}
return nIndex - i + 1;
}
}
}
return 0;
}
private string GetComment1(string strText, int nIndex) {
for (int i = nIndex + 3; i < strText.Length; i++) {
if (strText[i] == '/' && strText[i - 1] == '*') {
return strText.Substring(nIndex, i - nIndex + 1);
}
}
return strText.Substring(nIndex);
}
private string GetComment2(string strText, int nIndex) {
for (int i = nIndex + 2; i < strText.Length; i++) {
switch (strText[i]) {
case '\r':
case '\n':
return strText.Substring(nIndex, i - nIndex);
}
}
return strText.Substring(nIndex);
}
private string GetString1(string strText, int nIndex) {
for (int i = nIndex + 2; i < strText.Length; i++) {
if (strText[i] == '"') {
if (i + 1 < strText.Length && strText[i + 1] == '"') {
i++;
continue;
}
return strText.Substring(nIndex, i - nIndex + 1);
}
}
return strText.Substring(nIndex);
}
public string GetString2(string strText, int nIndex) {
for (int i = nIndex + 1; i < strText.Length; i++) {
if (strText[i] == '\\') {
i++;
continue;
}
if (strText[i] == '"') {
return strText.Substring(nIndex, i - nIndex + 1);
}
switch (strText[i]) {
case '\r':
case '\n':
return strText.Substring(nIndex, i - nIndex);
}
}
return strText.Substring(nIndex);
}
public string GetChar(string strText, int nIndex) {
for (int i = nIndex + 1; i < strText.Length; i++) {
if (strText[i] == '\\') {
i++;
continue;
}
if (strText[i] == '\'') {
return strText.Substring(nIndex, i - nIndex + 1);
}
switch (strText[i]) {
case '\r':
case '\n':
return strText.Substring(nIndex, i - nIndex);
}
}
return strText.Substring(nIndex);
}
public override void OnSelectionChanged(TextManager textManager, int nStart, int nLen) { }
public override void OnTextChanged(TextManager textManager, List<TextHistoryRecord> thrs) {
this.Init(textManager.GetText());
}
public override TextStyleRange GetStyleFromCharIndex(int nIndex) {
return TextStyleMonitor.GetStyleFromCharIndex(nIndex, m_lst_range);
//int nLeft = 0, nRight = m_lst_smb.Count - 1, nMid = 0;
//bool bFind = false;
//while (nLeft <= nRight) {
// nMid = (nLeft + nRight) >> 1;
// if (m_lst_smb[nMid].Index > nIndex) {
// nRight = nMid - 1;
// } else if (m_lst_smb[nMid].Index + m_lst_smb[nMid].Length <= nIndex) {
// nLeft = nMid + 1;
// } else {
// bFind = true;
// break;
// }
//}
//if (!bFind) {
// //return new TextStyleRange() { Index = nIndex, Length = 1, Style = new TextStyle() { ForeColor = this.DefaultColor } };
//}
//var ret = new TextStyleRange() {
// Index = m_lst_smb[nMid].Index,
// Length = m_lst_smb[nMid].Length
//};
//ret.Style.ForeColor = this.GetColorFromSymbolType(m_lst_smb[nMid].Type);
//return ret;
}
private TextStyle GetColorFromSymbolType(SymbolType smbType) {
switch (smbType) {
case SymbolType.Comment:
return this.CommentStyle;
case SymbolType.DocComment:
return this.DocCommentStyle;
case SymbolType.KeyWord:
return this.KeyWordStyle;
case SymbolType.String:
return this.StringStyle;
case SymbolType.Operator:
return this.OperatorStyle;
case SymbolType.Delimiter:
return this.DelimiterStyle;
case SymbolType.Number:
return this.NumberStyle;
case SymbolType.BuiltInType:
return this.BuiltInTypeStyle;
case SymbolType.Property:
return this.PropertyStyle;
case SymbolType.CustomType:
return this.CustomTypeStyle;
case SymbolType.FunctionDecl:
return this.FunctionDeclStyle;
case SymbolType.FunctionCall:
return this.FunctionCallStyle;
case SymbolType.FunctionBuiltIn:
return this.FunctionBuiltInStyle;
}
return this.DefaultStyle;
}
}
}

View File

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Text.RegularExpressions;
namespace ST.Library.UI.STTextBox
{
public class KeyWordStyleMonitor : TextStyleMonitor
{
private Regex m_reg_keywords;
private Regex m_reg_escape = new Regex(@"([\|\[\]\(\)\.\*\+\?\{\}\^\$\\])");
private Dictionary<string, TextStyle> m_dic = new Dictionary<string, TextStyle>();
private List<TextStyleRange> m_lst = new List<TextStyleRange>();
public override void Init(string strText) {
m_lst.Clear();
int nIndex = 0;
var ms = m_reg_keywords.Matches(strText);
foreach (Match m in ms) {
if (nIndex != m.Index) {
m_lst.Add(new TextStyleRange() {
Index = nIndex,
Length = m.Index - nIndex
});
}
m_lst.Add(new TextStyleRange() {
Index = m.Index,
Length = m.Length,
Style = m_dic[m.Value]
});
nIndex = m.Index + m.Length;
}
if (nIndex < strText.Length) {
m_lst.Add(new TextStyleRange() {
Index = nIndex,
Length = strText.Length - nIndex
});
}
}
public void Add(string strKeyWord, TextStyle style) {
if (m_dic.ContainsKey(strKeyWord)) {
m_dic[strKeyWord] = style;
} else {
m_dic.Add(strKeyWord, style);
}
this.InitRegex();
}
public void AddRangle(string[] strKeyWords, TextStyle style) {
foreach (var v in strKeyWords) {
if (m_dic.ContainsKey(v)) {
m_dic[v] = style;
} else {
m_dic.Add(v, style);
}
}
this.InitRegex();
}
public TextStyle Get(string strKeyWord) {
if (m_dic.ContainsKey(strKeyWord)) {
return m_dic[strKeyWord];
}
return TextStyle.Empty;
}
public bool Remove(string strKeyWord) {
if (!m_dic.ContainsKey(strKeyWord)) {
return false;
}
m_dic.Remove(strKeyWord);
this.InitRegex();
return true;
}
private void InitRegex() {
var arr = m_dic.Keys.ToArray();
for (int i = 0; i < arr.Length; i++) {
arr[i] = m_reg_escape.Replace(arr[i], "\\$1");
}
m_reg_keywords = new Regex("\\b(" + string.Join("|", arr) + ")\\b");
}
public override void OnSelectionChanged(TextManager textManager, int nStart, int nLen) { }
public override void OnTextChanged(TextManager textManager, List<TextHistoryRecord> thrs) {
this.Init(textManager.GetText());
}
public override TextStyleRange GetStyleFromCharIndex(int nIndex) {
return TextStyleMonitor.GetStyleFromCharIndex(nIndex, m_lst);
}
}
}

View File

@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
public class LinkStyleMonitor : ITextStyleMonitor
{
private Regex LinkRegex { get; set; }
public TextStyle Style { get; set; }
private List<TextStyleRange> m_lst;
public LinkStyleMonitor() {
this.LinkRegex = new Regex(@"https?://[a-zA-Z0-9-./#?&%+_]+");
this.Style = new TextStyle() {
ForeColor = Color.Blue,
UnderLineColor = Color.Blue,
FontStyle = FontStyle.Underline
};
}
public void Init(string strText) {
List<TextStyleRange> lst = new List<TextStyleRange>();
foreach (Match m in this.LinkRegex.Matches(strText)) {
lst.Add(new TextStyleRange() {
Index = m.Index,
Length = m.Length,
Style = this.Style
});
}
m_lst = TextStyleMonitor.FillDefaultStyle(lst, strText.Length, TextStyle.Empty);
}
public void OnSelectionChanged(TextManager textManager, int nStart, int nLen) { }
public void OnTextChanged(TextManager textManager, List<TextHistoryRecord> thrs) {
this.Init(textManager.GetText());
}
public TextStyleRange GetStyleFromCharIndex(int nIndex) {
return TextStyleMonitor.GetStyleFromCharIndex(nIndex, m_lst);
}
}
}

View File

@ -1,66 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
public class SelectionStyleMonitor : ITextStyleMonitor
{
public TextStyle Style { get; set; }
private static WordSplitter m_spliter = new WordSplitter();
private List<TextStyleRange> m_lst = new List<TextStyleRange>();
public SelectionStyleMonitor() {
this.Style = new TextStyle() {
BackColor = Color.FromArgb(50, 255, 0, 0)
};
}
public void Init(string strText) {
//throw new NotImplementedException();
}
public void OnSelectionChanged(TextManager textManager, int nStart, int nLen) {
//throw new NotImplementedException()
m_lst.Clear();
m_lst.Add(new TextStyleRange() {
Index = 0,
Length = textManager.TextLength,
Style = TextStyle.Empty
});
if (nLen == 0) return;
var line = textManager.GetLineFromCharIndex(nStart);
string strKey = string.Empty;
m_spliter.Each(line.RawString, nStart - line.IndexOfFirstChar, (str, ns, nl) => {
if (ns + line.IndexOfFirstChar == nStart && nLen == nl) {
strKey = str.Substring(ns, nl);
}
return false;
});
if (!string.IsNullOrEmpty(strKey)) {
string strText = textManager.GetText();
List<TextStyleRange> lst = new List<TextStyleRange>();
foreach (Match m in Regex.Matches(strText, "\\b" + strKey + "\\b")) {
lst.Add(new TextStyleRange() {
Index = m.Index,
Length = m.Length,
Style = this.Style
});
}
m_lst = TextStyleMonitor.FillDefaultStyle(lst, strText.Length, TextStyle.Empty);
}
}
public void OnTextChanged(TextManager textManager, List<TextHistoryRecord> thrs) {
//throw new NotImplementedException();
}
public TextStyleRange GetStyleFromCharIndex(int nIndex) {
return TextStyleMonitor.GetStyleFromCharIndex(nIndex, m_lst);
}
}
}

View File

@ -1,181 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public abstract class TextBoundary : ITextBoundary
{
public enum Type
{
Other,
Double_Quote,
Single_Quote,
Hebrew_Letter,
CR,
LF,
Newline,
Extend,
Regional_Indicator,
Format,
Katakana,
ALetter,
MidLetter,
MidNum,
MidNumLet,
Numeric,
ExtendNumLet,
ZWJ,
WSegSpace,
Extended_Pictographic,
Control,
SpacingMark,
L,
V,
T,
LV,
LVT,
Prepend,
E_Base,
E_Modifier,
Glue_After_Zwj,
E_Base_GAZ,
Custom_Property_Ascii
}
protected struct RangeInfo
{
public int Start;
public int End;
public int Type;
}
public List<string> Split(string strText) {
List<string> lst_result = new List<string>(strText.Length);
this.SplitPrivate(strText, lst_result, 0, null, null);
return lst_result;
}
public int GetCount(string strText) {
int nLen = this.SplitPrivate(strText, null, 0, null, null);
return nLen;
}
public void Each(string strText, EachVoidCallBack cb) {
this.SplitPrivate(strText, null, 0, cb, null);
}
public void Each(string strText, int nIndex, EachVoidCallBack cb) {
this.SplitPrivate(strText, null, nIndex, cb, null);
}
public void Each(string strText, EachBoolCallBack cb) {
this.SplitPrivate(strText, null, 0, null, cb);
}
public void Each(string strText, int nIndex, EachBoolCallBack cb) {
this.SplitPrivate(strText, null, nIndex, null, cb);
}
public static int GetCodePoint(string strText, int nIndex) {
if (strText[nIndex] < '\uD800' || strText[nIndex] > '\uDFFF') {
return strText[nIndex];
}
if (char.IsHighSurrogate(strText, nIndex)) {
if (nIndex + 1 >= strText.Length) {
return 0;
}
} else {
if (--nIndex < 0) {
return 0;
}
}
return ((strText[nIndex] & 0x03FF) << 10) + (strText[nIndex + 1] & 0x03FF) + 0x10000;
}
private int SplitPrivate(string strText, List<string> lst_result, int nIndexCurrent, EachVoidCallBack cb_void, EachBoolCallBack cb_bool) {
int nCounter = 0;
List<int> lst_history_break_type = new List<int>();
if (string.IsNullOrEmpty(strText) || nIndexCurrent >= strText.Length) {
return 0;
}
int nIndexCharStart = 0, nCharLen = 0, nLastCharLen = 0;
int nCodePoint = 0;
int nLeftBreakType = 0, nRightBreakType = 0;
while (nIndexCurrent < strText.Length && char.IsLowSurrogate(strText, nIndexCurrent)) {
nIndexCurrent++;
nCharLen++;
}
if (nCharLen != 0) {
nCounter++;
if (!this.CharCompleted(strText, nIndexCurrent - nCharLen, nCharLen, lst_result, cb_void, cb_bool)) {
return nCounter;
}
}
nIndexCharStart = nIndexCurrent;
nCodePoint = TextBoundary.GetCodePoint(strText, nIndexCurrent);
nLastCharLen = nCodePoint >= 0x10000 ? 2 : 1; // >= 0x10000 is double char
nLeftBreakType = this.GetBreakProperty(nCodePoint);
nIndexCurrent += nLastCharLen;
nCharLen = nLastCharLen;
lst_history_break_type.Add(nLeftBreakType);
while (nIndexCurrent < strText.Length) {
nCodePoint = TextBoundary.GetCodePoint(strText, nIndexCurrent);
nLastCharLen = nCodePoint >= 0x10000 ? 2 : 1; // >= 0x10000 is double char
nRightBreakType = this.GetBreakProperty(nCodePoint);
if (this.ShouldBreak(nRightBreakType, lst_history_break_type)) {
nCounter++;
if (!this.CharCompleted(strText, nIndexCharStart, nCharLen, lst_result, cb_void, cb_bool)) {
return nCounter;
}
nIndexCharStart = nIndexCurrent;
nCharLen = nLastCharLen;
lst_history_break_type.Clear();
} else {
nCharLen += nLastCharLen;
}
lst_history_break_type.Add(nRightBreakType);
nIndexCurrent += nLastCharLen;
nLeftBreakType = nRightBreakType;
}
if (nCharLen != 0) {
nCounter++;
this.CharCompleted(strText, nIndexCharStart, nCharLen, lst_result, cb_void, cb_bool);
}
return nCounter;
}
private bool CharCompleted(string strText, int nIndex, int nLen, List<string> lst_result, EachVoidCallBack cb_void, EachBoolCallBack cb_bool) {
//return value...[true:continue]...[false:break]
if (lst_result != null) {
lst_result.Add(strText.Substring(nIndex, nLen));
}
if (cb_void != null) {
cb_void(strText, nIndex, nLen);
} else if (cb_bool != null && !cb_bool(strText, nIndex, nLen)) {
return false;
}
return true;
}
protected abstract bool ShouldBreak(int nRightBreakType, List<int> lstHistoryBreakType);
protected abstract int GetBreakProperty(int nCodePoint);
protected static int BinarySearchRangeFromList(int nStart, int nEnd, int nValue, List<RangeInfo> lst) {
if (nEnd < nStart) {
return 0;
}
int nMid = nStart + (nEnd - nStart) / 2;
if (lst[nMid].Start > nValue) {
return TextBoundary.BinarySearchRangeFromList(nStart, nMid - 1, nValue, lst);
} else if (lst[nMid].End < nValue) {
return TextBoundary.BinarySearchRangeFromList(nMid + 1, nEnd, nValue, lst);
} else {
return lst[nMid].Type;
}
}
}
}

View File

@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public class TextHistory : ITextHistory
{
private int m_nIndex;
private int m_nCount;
private int m_nMax;
private TextHistoryRecord[][] m_arr;
public TextHistory(int nCount) {
m_nMax = nCount;
m_arr = new TextHistoryRecord[nCount][];
}
public void SetHistory(TextHistoryRecord[] histories) {
if (m_nIndex == m_nMax) {
for (int i = 1; i < m_arr.Length; i++) {
m_arr[i - 1] = m_arr[i];
}
m_nIndex--;
}
m_arr[m_nIndex++] = histories;
m_nCount = m_nIndex;
}
public TextHistoryRecord[] GetUndo() {
if (m_nIndex == 0) { //not have history
return null;
}
return m_arr[--m_nIndex];
}
public TextHistoryRecord[] GetRedo() {
if (m_nIndex == m_nCount) {
return null;
}
return m_arr[m_nIndex++];
}
public void Clear() {
m_nIndex = m_nCount = 0;
}
}
}

View File

@ -1,73 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public abstract class TextStyleMonitor : ITextStyleMonitor
{
public static List<TextStyleRange> FillDefaultStyle(List<TextStyleRange> lst, int nTextLength, TextStyle style) {
List<TextStyleRange> lstRet = new List<TextStyleRange>();
int nIndex = 0;
foreach (var tsr in lst) {
if (nIndex != tsr.Index) {
lstRet.Add(new TextStyleRange() {
Index = nIndex,
Length = tsr.Index - nIndex,
Style = style
});
}
lstRet.Add(new TextStyleRange() {
Index = tsr.Index,
Length = tsr.Length,
Style = tsr.Style
});
nIndex = tsr.Index + tsr.Length;
}
if (nIndex < nTextLength) {
lstRet.Add(new TextStyleRange() {
Index = nIndex,
Length = nTextLength - nIndex
});
}
return lstRet;
}
public static TextStyleRange GetStyleFromCharIndex(int nIndex, List<TextStyleRange> lst) {
if (lst == null || lst.Count == 0) {
return TextStyleRange.Empty;
}
int nLeft = 0, nRight = lst.Count - 1, nMid = 0;
while (nLeft <= nRight) {
nMid = (nLeft + nRight) >> 1;
if (lst[nMid].Index > nIndex) {
nRight = nMid - 1;
} else if (lst[nMid].Index + lst[nMid].Length <= nIndex) {
nLeft = nMid + 1;
} else {
return lst[nMid];
}
}
if (nIndex < lst[nMid].Index) {
if (nMid == 0) return new TextStyleRange() { Index = 0, Length = lst[0].Index };
return new TextStyleRange() {
Index = lst[nMid - 1].Index + lst[nMid - 1].Length,
Length = lst[nMid].Index - lst[nMid - 1].Index - lst[nMid - 1].Length
};
}
if (nMid == lst.Count - 1) return new TextStyleRange() {
Index = lst[nMid].Index + lst[nMid].Length, Length = int.MaxValue
};
return new TextStyleRange() {
Index = lst[nMid].Index + lst[nMid].Length,
Length = lst[nMid + 1].Index - lst[nMid].Index - lst[nMid].Length
};
}
public abstract void Init(string strText);
public abstract void OnSelectionChanged(TextManager textManager, int nStart, int nLen);
public abstract void OnTextChanged(TextManager textManager, List<TextHistoryRecord> thrs);
public abstract TextStyleRange GetStyleFromCharIndex(int nIndex);
}
}

View File

@ -1,408 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
public class NoWrapTextView : TextView
{
private struct NoWrapLineCache
{
public int Index;
public int Offset;
public override string ToString() {
return "[" + this.Index + "," + this.Offset + "]";
}
}
private int m_nMaxLineWidth;
//private HashSet<TextLine> m_hs_changed = new HashSet<TextLine>();
private Dictionary<TextLine, List<NoWrapLineCache>> m_dic_nowrap_line = new Dictionary<TextLine, List<NoWrapLineCache>>();
private StringFormat m_sf = new StringFormat(StringFormat.GenericTypographic) {
Alignment = StringAlignment.Far,
LineAlignment = StringAlignment.Center
};
public override void OnInitAllText() {
//m_hs_changed.Clear();
m_dic_nowrap_line.Clear();
var c = base.Core;
foreach (var line in c.TextManager) {
this.AddLine(line, c.ITextBoxRender);
}
}
public override void OnLineAdded(ISTTextBoxRender render, TextManagerLineEventArgs e) {
this.AddLine(e.Line, render);
}
public override void OnLineRemoved(ISTTextBoxRender render, TextManagerLineEventArgs e) {
//m_hs_changed.Remove(e.Line);
m_dic_nowrap_line.Remove(e.Line);
}
public override void OnLineChanged(ISTTextBoxRender render, TextManagerLineEventArgs e) {
//m_hs_changed.Add(e.Line);
var c = base.Core;
int nElementIndex = 0;
var li = this.GetLineCacheFromIndex(e.Line, e.History.Index - e.Line.IndexOfFirstChar, out nElementIndex);
int nEachIndex = li.Index;
e.Line.Tag = li.Offset;
int nCounter = 0;
List<NoWrapLineCache> lst = null;
if (m_dic_nowrap_line.ContainsKey(e.Line)) {
lst = m_dic_nowrap_line[e.Line];
lst.RemoveRange(nElementIndex, lst.Count - nElementIndex);
} else {
lst = new List<NoWrapLineCache>();
}
c.IGraphemeSplitter.Each(e.Line.RawString, nEachIndex, (str, nStart, nLen) => {
string strChar = str.Substring(nStart, nLen);
if (nCounter++ % 500 == 0) {
lst.Add(new NoWrapLineCache() {
Offset = _LineWidth(e.Line),
Index = nStart
});
}
e.Line.Tag = _LineWidth(e.Line) + c.GetStringWidth(strChar, c.GetStyleFromCharIndex(e.Line.IndexOfFirstChar + nStart), _LineWidth(e.Line));
if (_LineWidth(e.Line) > m_nMaxLineWidth) {
m_nMaxLineWidth = _LineWidth(e.Line);
}
return true;
});
if (lst.Count > 1) {
if (!m_dic_nowrap_line.ContainsKey(e.Line)) {
m_dic_nowrap_line.Add(e.Line, lst);
}
}
}
public override int GetCurrentCharOffset() {
var c = base.Core;
return c.Caret.X - base.TextRectangle.X + c.Scroll.XOffset;
//throw new NotImplementedException();
}
public override FindInfo FindFromPoint(Point pt) {
var c = base.Core;
FindInfo fi = new FindInfo();
int nXStart = base.TextRectangle.X;
int nX = nXStart - c.Scroll.XOffset, nIndexChar = 0, nCharWidth = 0;
int nIndexLine = c.Scroll.YValue + ((pt.Y - base.TextRectangle.Y) / c.LineHeight);// c.ITextRender.GetFontHeight());
if (nIndexLine >= c.TextManager.LineCount) {//Note: Count = 0;outofrange...
nIndexLine = c.TextManager.LineCount - 1;
} else if (nIndexLine < 0) {
nIndexLine = 0;
}
TextLine line = c.TextManager[nIndexLine];
fi.Line = line;
fi.IndexOfLine = nIndexLine;
int nElementIndex = 0;
var li = this.GetLineCacheFromOffset(line, c.Scroll.XOffset + (pt.X - base.TextRectangle.Left), out nElementIndex);
nIndexChar = li.Index;
nX += li.Offset;
//using (var dt = c.GetDrawingTools()) {
c.ITextBoxRender.BeginPaint();
c.IGraphemeSplitter.Each(line.RawString, nIndexChar, (str, nStart, nLen) => {
if (str[nStart] == '\r') return false;
if (str[nStart] == '\n') return false;
string strChar = str.Substring(nStart, nLen);
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), nX - base.TextRectangle.X + c.Scroll.XOffset);
if (nX + nCharWidth > pt.X) {
fi.Find = true;
if (pt.X - nX >= nCharWidth / 2) {
fi.IndexOfCharInLine = nIndexChar + nLen;
fi.Location = new Point(nX + nCharWidth, base.TextRectangle.Y + (nIndexLine - c.Scroll.YValue) * c.LineHeight);
} else {
fi.IndexOfCharInLine = nIndexChar;
fi.Location = new Point(nX, base.TextRectangle.Y + (nIndexLine - c.Scroll.YValue) * c.LineHeight);
}
return false;
}
nX += nCharWidth;
nIndexChar += nLen;
return true;
});
c.ITextBoxRender.EndPaint();
//}
if (!fi.Find) {
fi.IndexOfCharInLine = nIndexChar;
fi.Location = new Point(nX, base.TextRectangle.Y + (nIndexLine - c.Scroll.YValue) * c.LineHeight);
}
fi.Find = true;
return fi;
}
public override FindInfo FindFromCharIndex(int nIndex) {
var c = base.Core;
int nIndexOfLine = c.TextManager.GetLineIndexFromCharIndex(nIndex);
TextLine stLine = c.TextManager[nIndexOfLine];
if (stLine == null) {
return new FindInfo();
}
return this.FindFromCharIndex(nIndexOfLine, nIndex - stLine.IndexOfFirstChar);
}
private FindInfo FindFromCharIndex(int nIndexOfLine, int nIndex) {
var c = base.Core;
//using (var dt = base.Core.GetDrawingTools()) {
return this.FindFromCharIndex(c.ITextBoxRender, nIndexOfLine, nIndex);
//}
}
/// <summary>
///
/// </summary>
/// <param name="g"></param>
/// <param name="stLine"></param>
/// <param name="nIndex">Index of stLine</param>
/// <returns></returns>
private FindInfo FindFromCharIndex(ISTTextBoxRender render, int nIndexOfLine, int nIndex) {
var c = base.Core;
TextLine line = c.TextManager[nIndexOfLine];
int nX = 0, nIndexEach = 0, nCharWidth;
int nXStart = base.TextRectangle.X;
nX = nXStart - c.Scroll.XOffset;
int nElementIndex = 0;
var li = this.GetLineCacheFromIndex(line, nIndex, out nElementIndex);
nIndexEach = li.Index;
nX += li.Offset;
c.IGraphemeSplitter.Each(line.RawString, nIndexEach, (str, nStart, nLen) => {
if (nStart >= nIndex) {
return false;
}
string strChar = str.Substring(nStart, nLen);
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), nX - base.TextRectangle.X + c.Scroll.XOffset);
nX += nCharWidth;
return true;
});
return new FindInfo() {
Line = line,
IndexOfLine = nIndexOfLine,
IndexOfCharInLine = nIndex,
Location = new Point(nX, base.TextRectangle.Y + (nIndexOfLine - c.Scroll.YValue) * c.LineHeight)// c.ITextRender.GetFontHeight())
};
}
protected override void OnDrawLineSelectionBackground(ISTTextBoxRender render, TextLine line, int nLineIndex, STTextBoxSelectionInfo selection, int nY) {
var c = base.Core;
if (line.IndexOfFirstChar >= selection.EndIndex) {
return;
}
if (line.IndexOfFirstChar + line.RawString.Length <= selection.StartIndex) {
return;
}
int nLeft = base.TextRectangle.Left, nWidth = _LineWidth(line) - c.Scroll.XOffset;
if (line.IndexOfFirstChar < selection.StartIndex) {
nLeft = this.FindFromCharIndex(render, nLineIndex, c.Selection.StartIndex - line.IndexOfFirstChar).Location.X;
nWidth -= nLeft - base.TextRectangle.X;
}
if (selection.EndIndex <= line.IndexOfFirstChar + line.RawString.Length) {
nWidth = this.FindFromCharIndex(render, nLineIndex, c.Selection.EndIndex - line.IndexOfFirstChar).Location.X;
nWidth -= nLeft;
}
if (nLeft + nWidth > base.TextRectangle.Right) {
nWidth -= nLeft + nWidth - base.TextRectangle.Right;
}
render.FillRectangle(c.TextBox.SelectionColor, nLeft, nY, nWidth, c.LineHeight);
}
protected override int OnDrawLine(ISTTextBoxRender render, TextLine line, int nX, int nY) {
var c = base.Core;
int nLineSpacing = c.TextBox.GetIntYSize(c.TextBox.LineSpacing) / 2;
int nIndexEach = 0;
Rectangle rect_char = new Rectangle(nX - c.Scroll.XOffset, nY, 0, c.LineHeight);
if (string.IsNullOrEmpty(line.RawString)) {
return c.LineHeight;
}
int nElementIndex = 0, nCharSpacing = c.TextBox.GetIntXSize(c.TextBox.CharSpacing);// / 2;
var li = this.GetLineCacheFromOffset(line, c.Scroll.XOffset, out nElementIndex);
nIndexEach = li.Index;
rect_char.X += li.Offset;
int nCurrentCharIndex = line.IndexOfFirstChar + nIndexEach;
bool bIsEmoji = false;
c.IGraphemeSplitter.Each(line.RawString, nIndexEach, (str, nStart, nLen) => {
string strChar = str.Substring(nStart, nLen);
if (c.IsEmoji(strChar)) {
bIsEmoji = true;
rect_char.Width = c.FontHeight;
} else {
if (nLen > 1 && strChar[nLen - 1] >= '\uFE00' && strChar[nLen - 1] <= '\uFE0F') {
strChar = str.Substring(nStart, nLen - 1);
}
bIsEmoji = false;
rect_char.Width = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), rect_char.X - base.TextRectangle.X + c.Scroll.XOffset) + nCharSpacing;
}
nCurrentCharIndex = line.IndexOfFirstChar + nStart;
if (rect_char.Right <= base.TextRectangle.Left) {
rect_char.X += rect_char.Width;
return true;
}
if (bIsEmoji) {
bool bSelected = nCurrentCharIndex >= c.Selection.StartIndex && nCurrentCharIndex < c.Selection.EndIndex;
c.IEmojiRender.DrawEmoji(render, strChar, rect_char.X + (nCharSpacing >> 1), nY + nLineSpacing, c.FontHeight, bSelected);
} else {
c.ITextBoxRender.DrawString(strChar, c.GetStyleFromCharIndex(nCurrentCharIndex), rect_char);
}
if (rect_char.Right > base.TextRectangle.Right) {
return false;
}
rect_char.X += rect_char.Width;
return true;
});
return c.LineHeight;
}
protected override void OnDrawHead(ISTTextBoxRender render, int nStartLineIndex) {
render.FillRectangle(base.HeadBackgroundColor, base.HeadRectangle);
var c = base.Core;
Rectangle rect_linenumber = new Rectangle(base.HeadRectangle.X, base.HeadRectangle.Y, base.LineNumberWidth - c.TextBox.GetIntXSize(10), c.LineHeight);
//Rectangle rect_status = new Rectangle(base.HeadRectangle.Right - c.TextBox.GetIntXSize(base.LineStatusWidth), rect_linenumber.Y, c.TextBox.GetIntXSize(base.LineStatusWidth), c.LineHeight);
for (int i = nStartLineIndex; i < c.TextManager.LineCount; i++) {
if (base.ShowLineNumber) {
render.DrawString((i + 1).ToString(), c.TextBox.Font, base.LineNumberColor, rect_linenumber, m_sf);
}
//if (base.ShowLineStatus) {
// if (m_hs_changed.Contains(c.TextManager[i])) {
// render.FillRectangle(base.LineStatusColor, rect_status);
// }
//}
rect_linenumber.Y += c.LineHeight;
//rect_status.Y += c.LineHeight;
if (rect_linenumber.Y >= base.HeadRectangle.Bottom) break;
}
}
public override int GetLineIndexFromYScroll(int nYValue) {
//if (nYValue > base.Core.Scroll.MaxYValue) {
// return base.Core.Scroll.MaxYValue;
//}
//if (nYValue < 0) {
// return 0;
//}
return nYValue;
}
private int _LineWidth(TextLine line) {
if (line.Tag == null) {
return 0;
}
if (line.Tag is int) {
return (int)line.Tag;
}
return 0;
}
private void AddLine(TextLine line, ISTTextBoxRender render) {
//m_hs_changed.Add(line);
var c = base.Core;
int nCounter = 0;
List<NoWrapLineCache> lst = new List<NoWrapLineCache>();
c.IGraphemeSplitter.Each(line.RawString, (str, nStart, nLen) => {
string strChar = str.Substring(nStart, nLen);
if (nCounter++ % 500 == 0) {
lst.Add(new NoWrapLineCache() {
Offset = _LineWidth(line),
Index = nStart
});
}
line.Tag = _LineWidth(line) + c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), _LineWidth(line));
if (_LineWidth(line) > m_nMaxLineWidth) {
m_nMaxLineWidth = _LineWidth(line);
}
return true;
});
if (lst.Count > 1) {
m_dic_nowrap_line.Add(line, lst);
}
}
private NoWrapLineCache GetLineCacheFromOffset(TextLine line, int nOffset) {
int n = 0;
return this.GetLineCacheFromOffset(line, nOffset, out n);
}
private NoWrapLineCache GetLineCacheFromOffset(TextLine line, int nOffset, out int nElementIndex) {
nElementIndex = 0;
if (!m_dic_nowrap_line.ContainsKey(line)) {
return new NoWrapLineCache();
}
var lst = m_dic_nowrap_line[line];
int nLeft = 0, nRight = lst.Count - 1;
while (nLeft <= nRight) {
nElementIndex = (nLeft + nRight) >> 1;
if (nOffset >= lst[nElementIndex].Offset) {
if (nElementIndex + 1 >= lst.Count || nOffset < lst[nElementIndex + 1].Offset) {
return lst[nElementIndex];
}
nLeft = nElementIndex + 1;
} else {
nRight = nElementIndex - 1;
}
}
return lst[nElementIndex];
}
private NoWrapLineCache GetLineCacheFromIndex(TextLine line, int nIndex) {
int n = 0;
return this.GetLineCacheFromIndex(line, nIndex, out n);
}
private NoWrapLineCache GetLineCacheFromIndex(TextLine line, int nIndex, out int nElementIndex) {
nElementIndex = 0;
if (!m_dic_nowrap_line.ContainsKey(line)) {
return new NoWrapLineCache();
}
var lst = m_dic_nowrap_line[line];
int nLeft = 0, nRight = lst.Count - 1;
while (nLeft <= nRight) {
nElementIndex = (nLeft + nRight) >> 1;
if (nIndex >= lst[nElementIndex].Index) {
if (nElementIndex + 1 >= lst.Count || nIndex < lst[nElementIndex + 1].Index) {
return lst[nElementIndex];
}
nLeft = nElementIndex + 1;
} else {
nRight = nElementIndex - 1;
}
}
return lst[nElementIndex];
}
public override void SetCaretPostion(int nCharIndex) {
var c = this.Core;
int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(nCharIndex);
var line = c.TextManager[nLineIndex];
var cache = this.GetLineCacheFromIndex(line, nCharIndex - line.IndexOfFirstChar);
int nWidth = cache.Offset, nIndexTemp = line.IndexOfFirstChar + cache.Index;
c.ITextBoxRender.BeginPaint();
c.IGraphemeSplitter.Each(line.RawString, cache.Index, (str, nStart, nLen) => {
if (nStart >= nCharIndex - line.IndexOfFirstChar) return false;
string strChar = str.Substring(nStart, nLen);
nWidth += c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), nWidth);
nIndexTemp = line.IndexOfFirstChar + nStart + nLen;
return true;
});
c.ITextBoxRender.EndPaint();
c.Caret.IndexOfLine = nLineIndex;
c.Caret.IndexOfChar = nIndexTemp;
this.SetCaretPostion(nWidth - c.Scroll.XOffset + this.TextRectangle.X, this.TextRectangle.Y + (nLineIndex - c.Scroll.YValue) * c.LineHeight);
}
public override void OnCalcScroll(STTextBoxScrollInfo scrollInfo) {
var c = base.Core;
c.Scroll.MaxYValue = c.TextManager.LineCount - base.TextRectangle.Height / c.LineHeight + 2;
if (c.Scroll.MaxYValue < 0) {
c.Scroll.MaxYValue = 0;
}
c.Scroll.MaxXValue = (m_nMaxLineWidth - base.TextRectangle.Width) / c.Scroll.XIncrement + 2;
if (c.Scroll.MaxXValue < 0) {
c.Scroll.MaxXValue = 0;
}
}
}
}

View File

@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
public class SingleTextView : NoWrapTextView
{
public SingleTextView() {
base.ShowLineNumber = false;
}
public override void OnTextStartChange(ISTTextBoxRender render, TextManagerTextEventArgs e) {
base.OnTextStartChange(render, e);
for (int i = 0; i < e.TextHistoryRecord.Count; i++) {
var r = e.TextHistoryRecord[i];
r.NewText = r.NewText.Replace("\r", "").Replace("\n", "");
e.TextHistoryRecord[i] = r;
}
}
public override void OnCalcTextRectangle() {
base.OnCalcTextRectangle();
Rectangle rect_text = base.TextRectangle;
Rectangle rect_head = base.HeadRectangle;
rect_text.Height = base.Core.LineHeight + base.Core.TextBox.LineSpacing;
rect_text.Y = (base.Core.TextBox.Height - rect_text.Height) / 2;
rect_head.Height = rect_text.Height;
rect_head.Y = rect_text.Y;
base.TextRectangle = rect_text;
base.HeadRectangle = rect_head;
}
public override void OnCalcScroll(STTextBoxScrollInfo scrollInfo) {
base.OnCalcScroll(scrollInfo);
var c = base.Core;
c.Scroll.MaxYValue = c.TextManager.LineCount - base.TextRectangle.Height / c.LineHeight;
if (c.Scroll.MaxYValue < 0) {
c.Scroll.MaxYValue = 0;
}
}
}
}

View File

@ -1,261 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CPF;
namespace ST.Library.UI.STTextBox
{
public abstract class TextView : ITextView
{
private bool _ShowLineNumber = true;
public bool ShowLineNumber {
get { return _ShowLineNumber; }
set {
if (value == _ShowLineNumber) return;
_ShowLineNumber = value;
if (this.Core == null) return;
this.OnCalcTextRectangle();
this.OnCalcScroll(this.Core.Scroll);
this.SetCaretPostion(this.Core.Caret.IndexOfChar);
this.Invalidate();
}
}
private Color _HeadBackgroundColor = Color.FromArgb(120, Color.LightGray);
public Color HeadBackgroundColor {
get { return _HeadBackgroundColor; }
set { _HeadBackgroundColor = value; }
}
private Color _TextViewBackgroundColor = Color.Transparent;
public Color TextViewBackgroundColor {
get { return _TextViewBackgroundColor; }
set { _TextViewBackgroundColor = value; }
}
private Color _LineNumberColor = Color.Black;
public Color LineNumberColor {
get { return _LineNumberColor; }
set { _LineNumberColor = value; }
}
public int LineNumberWidth { get; private set; }
public Rectangle HeadRectangle { get; protected set; }
public Rectangle TextRectangle { get; protected set; }
protected STTextBox.Core Core { get; private set; }
public abstract int GetCurrentCharOffset();
public void Init(STTextBox.Core textBoxCore) {
this.Core = textBoxCore;
this.OnInitAllText();
}
public abstract void SetCaretPostion(int nCharIndex);
public virtual FindInfo SetCaretPostion(Point pt) {
var fi = this.FindFromPoint(pt);
if (!fi.Find) {
return fi;
}
this.Core.Caret.CopyFromFindInfo(fi);
this.SetCaretPostion(fi.Location.X, fi.Location.Y);
return fi;
}
protected virtual void SetCaretPostion(int nX, int nY) {
var caret = this.Core.Caret;
caret.X = nX;
caret.Y = nY;
if (!this.TextRectangle.Contains(new Point(nX, nY))) {
if (!caret.Visable) return;
Win32.HideCaret(this.Core.TextBox.Handle);
caret.Visable = false;
} else {
Win32.SetCaretPos(nX, nY);
if (!caret.Visable) {
caret.Visable = true;
Win32.ShowCaret(this.Core.TextBox.Handle);
}
}
}
public virtual void ScrollXToMuosePoint(int nX) {
var c = this.Core;
nX -= c.ViewRectangle.X;
nX -= c.Scroll.HThumbRect.Width / 2;
if (nX < 0) {
nX = 0;
} else if (nX + c.Scroll.HThumbRect.Width > c.Scroll.HBackRect.Width) {
nX = c.Scroll.HBackRect.Width - c.Scroll.HThumbRect.Width;
}
int nTemp = (int)((float)nX / (c.Scroll.HBackRect.Width - c.Scroll.HThumbRect.Width) * c.Scroll.MaxXValue);
c.Scroll.XValue = nTemp;
this.SetCaretPostion(c.Caret.IndexOfChar);
}
public virtual void ScrollYToMousePoint(int nY) {
var c = this.Core;
nY -= c.ViewRectangle.Y;
nY -= c.Scroll.VThumbRect.Height / 2;
if (nY < 0) {
nY = 0;
} else if (nY + c.Scroll.VThumbRect.Height > c.Scroll.VBackRect.Height) {
nY = c.Scroll.VBackRect.Height - c.Scroll.VThumbRect.Height;
}
int nTemp = (int)((float)nY / (c.Scroll.VBackRect.Height - c.Scroll.VThumbRect.Height) * c.Scroll.MaxYValue);
c.Scroll.YValue = nTemp;
this.SetCaretPostion(c.Caret.IndexOfChar);
}
public virtual bool ScrollToCaret() {
var c = this.Core;
bool flag = false;
Point pt = c.Caret.Location;
if (pt.Y < this.TextRectangle.Y) {
c.Scroll.YValue += (pt.Y - this.TextRectangle.Y) / c.LineHeight;
flag = true;
} else if (pt.Y + c.LineHeight > this.TextRectangle.Bottom) {
int nIncrement = (int)Math.Ceiling((pt.Y + c.LineHeight - this.TextRectangle.Bottom) / (float)c.LineHeight);
c.Scroll.YValue += nIncrement;
flag = true;
}
if (pt.X >= this.TextRectangle.Right) {
int nIncrement = (int)Math.Ceiling((pt.X - this.TextRectangle.Right + 1) / (float)c.Scroll.XIncrement);
c.Scroll.XValue += nIncrement;
flag = true;
} else if (pt.X < this.TextRectangle.X) {
int nIncrement = ((int)Math.Ceiling((this.TextRectangle.X - pt.X) / (float)c.Scroll.XIncrement));
c.Scroll.XValue -= nIncrement;
flag = true;
}
if (flag) {
this.SetCaretPostion(c.Caret.IndexOfChar);
}
return flag;
}
public Point ControlToView(Point pt) {
var c = this.Core;
pt.X = pt.X - this.TextRectangle.X + this.Core.Scroll.XOffset;
pt.Y = pt.Y - c.TextBox.GetIntYSize(c.ViewRectangle.Y) + c.Scroll.YValue * c.LineHeight;
return pt;
}
public Point ViewToControl(Point pt) {
var c = this.Core;
pt.X = pt.X - c.Scroll.XOffset + this.TextRectangle.X;
pt.Y = pt.Y - c.Scroll.YValue * c.LineHeight + c.TextBox.GetIntYSize(c.ViewRectangle.Y);
return pt;
}
public void Invalidate() {
if (this.Core != null && this.Core.TextBox != null) {
this.Core.TextBox.Invalidate();
}
}
public void OnDrawView(ISTTextBoxRender render) {
var c = this.Core;
int nXStart = this.TextRectangle.X;
if (this._TextViewBackgroundColor.A > 0) { // fill background
Rectangle rect = c.ViewRectangle;
rect.X = this.HeadRectangle.Right;
rect.Width -= this.HeadRectangle.Width;
this.OnFillTextViewBackground(render, rect);
}
render.SetClip(this.TextRectangle);
//this.OnDrawSelectionBackground(dt, c.Selection); // fill selection background
// start draw line
int nY = this.TextRectangle.Y;
int nStartLineIndex = this.GetLineIndexFromYScroll(c.Scroll.YValue);
for (int i = nStartLineIndex; i < c.TextManager.LineCount; i++) {
TextLine line = c.TextManager[i];
if (!c.Selection.IsEmptySelection) {
this.OnDrawLineSelectionBackground(render, line, i, c.Selection, nY);
}
nY += this.OnDrawLine(render, line, nXStart, nY);
if (nY > c.ViewRectangle.Bottom) break;
}
// start draw line number
render.SetClip(this.HeadRectangle);
this.OnDrawHead(render, nStartLineIndex);
render.ResetClip();
}
protected virtual void OnFillTextViewBackground(ISTTextBoxRender render, Rectangle rect) {
render.FillRectangle(this.TextViewBackgroundColor, rect);
}
protected virtual void OnFillHeadBackground(ISTTextBoxRender render, Rectangle rect) {
render.FillRectangle(this._HeadBackgroundColor, rect);
}
protected abstract void OnDrawLineSelectionBackground(ISTTextBoxRender render, TextLine line, int nLineIndex, STTextBoxSelectionInfo selection, int nY);
protected abstract void OnDrawHead(ISTTextBoxRender render, int nStartLineIndex);
protected abstract int OnDrawLine(ISTTextBoxRender render, TextLine line, int nX, int nY);
public virtual void OnResize(EventArgs e) { }
public virtual void OnTextStartChange(ISTTextBoxRender render, TextManagerTextEventArgs e) { }
public virtual void OnTextChanged(ISTTextBoxRender render, TextManagerTextEventArgs e) { }
public virtual void OnLineCountChanged(ISTTextBoxRender render, EventArgs e) { }
public abstract void OnInitAllText();
public abstract void OnLineAdded(ISTTextBoxRender render, TextManagerLineEventArgs e);
public abstract void OnLineRemoved(ISTTextBoxRender render, TextManagerLineEventArgs e);
public abstract void OnLineChanged(ISTTextBoxRender render, TextManagerLineEventArgs e);
public abstract int GetLineIndexFromYScroll(int nYValue);
public abstract FindInfo FindFromPoint(Point pt);
public abstract FindInfo FindFromCharIndex(int nIndex);
public void OnSetCursor(MouseEventArgs e) {
var c = this.Core;
if (c.ViewRectangle.Contains(e.Location) && e.X < this.TextRectangle.X) {
c.Scroll.HoverScrollBar = STTextBoxScrollInfo.ScrollBarType.None;
this.SetCursor(Cursors.Arrow);
} else {
c.Scroll.HoverScrollBar = STTextBoxScrollInfo.ScrollBarType.None;
this.SetCursor(Cursors.IBeam);
}
}
private bool SetCursor(Cursor c) {
if (this.Core.TextBox.Cursor == c) {
return false;
}
this.Core.TextBox.Cursor = c;
return true;
}
public virtual void OnCalcTextRectangle() {
var c = this.Core;
string strLineCount = c.TextManager.LineCount.ToString();
this.Core.ITextBoxRender.BeginPaint();
this.LineNumberWidth = c.GetStringWidth("".PadLeft(strLineCount.Length, '8'), TextStyle.Empty, 0) + c.TextBox.GetIntXSize(20);
c.ITextBoxRender.EndPaint();
Rectangle rect = c.ViewRectangle;
Rectangle rect_temp = new Rectangle() {
X = rect.X,
Y = rect.Y,
Height = rect.Height
};
if (this._ShowLineNumber) {
rect_temp.Width += this.LineNumberWidth;
}
this.HeadRectangle = rect_temp;
rect_temp.X = this.HeadRectangle.Right + this.Core.TextBox.GetIntXSize(2);
rect_temp.Width = rect.Width - rect_temp.X - this.Core.TextBox.GetIntXSize(2) + rect.X;
this.TextRectangle = rect_temp;
}
public abstract void OnCalcScroll(STTextBoxScrollInfo scrollInfo);
}
}

View File

@ -1,720 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
public class WrapTextView : TextView
{
public Color LineNumberGuideColor { get; set; }
public bool ShowLineNumberGuide { get; set; }
public enum Method { Char, Word };
public enum Alignment { Left, Center, Right/*, Justify*/ }
private enum SubLineStatus
{
Start,
Middle,
End,
None
}
private class WrapLineInfo
{
public int ScreenLineOffset { get; set; }
public List<SubLineInfo> SubLines { get; set; }
public override string ToString() {
return "(" /*+ this.IndexOfLine + "," +*/ + this.ScreenLineOffset + "," + this.SubLines.Count + ")";
}
}
private struct WordInfo
{
public int Width;
public int CharCount;
}
private struct SubLineInfo
{
public int Index; // The first char index of sub-line
public int Length; // The text length
public int CharCount; // Grapheme count
public int Width; // Sub-Line width
public int X; // The X position to draw
//public float ExtraWidth; // The char space width
}
public Method WrapMethod { get; private set; }
public Alignment WrapAlignment { get; private set; }
private int m_n_line_count_start_change = 0;
private HashSet<TextLine> m_hs_changed_temp = new HashSet<TextLine>();
private StringFormat m_sf = new StringFormat(StringFormat.GenericTypographic) {
Alignment = StringAlignment.Far,
LineAlignment = StringAlignment.Center
};
public WrapTextView() : this(Method.Word, Alignment.Left) { }
public WrapTextView(Method method, Alignment alignment) {
this.WrapMethod = method;
this.WrapAlignment = alignment;
this.ShowLineNumberGuide = true;
this.LineNumberGuideColor = Color.Magenta;
}
public void SetWrap(Method method, Alignment alignment) {
this.WrapMethod = method;
this.WrapAlignment = alignment;
if (this.Core == null) return;
this.OnInitAllText();
}
public override int GetCurrentCharOffset() {
var c = base.Core;
TextLine line = c.Caret.Line;
var tag = _Tag(line);
int nSubIndex = 0;
int nCharIndex = c.Caret.IndexOfChar - line.IndexOfFirstChar;
foreach (var sub in tag.SubLines) {
if (nCharIndex >= sub.Index && nCharIndex <= sub.Index + sub.Length) {
break;
}
nSubIndex++;
}
var subLine = tag.SubLines[nSubIndex];
return c.Caret.X - base.TextRectangle.X - subLine.X;
}
public override void OnInitAllText() {
var c = base.Core;
c.ITextBoxRender.BeginPaint();
foreach (var line in base.Core.TextManager) {
this.CacheLine(line, base.Core.ITextBoxRender);
}
c.ITextBoxRender.EndPaint();
c.TextBox.Invalidate();
}
public override void OnLineAdded(ISTTextBoxRender render, TextManagerLineEventArgs e) {
this.CacheLine(e.Line, render);
m_hs_changed_temp.Add(e.Line);
}
private WrapLineInfo _Tag(TextLine line) {
WrapLineInfo ret = null;
if (line.Tag == null || !(line.Tag is WrapLineInfo)) {
line.Tag = ret = new WrapLineInfo();
return ret;
}
return (WrapLineInfo)line.Tag;
}
private void CacheLine(TextLine line, ISTTextBoxRender render) {
var tag = _Tag(line);
tag.SubLines = this.GetCache(line, render);
}
public override void OnLineRemoved(ISTTextBoxRender render, TextManagerLineEventArgs e) {
//m_hs_changed.Remove(e.Line);
m_hs_changed_temp.Remove(e.Line);
}
public override void OnLineChanged(ISTTextBoxRender render, TextManagerLineEventArgs e) {
//m_hs_changed.Add(e.Line);
m_hs_changed_temp.Add(e.Line);
}
private List<SubLineInfo> GetCache(TextLine line, ISTTextBoxRender render) {
var c = base.Core;
List<SubLineInfo> lst = null;
if (this.WrapMethod == Method.Char) {
lst = new List<SubLineInfo>();
this.GetCacheByChar(line, render, lst, 0, 0);
} else {
lst = this.GetCacheByWord(line, render);
}
for (int i = 0; i < lst.Count; i++) {
var sub = lst[i];
switch (this.WrapAlignment) {
case Alignment.Center:
sub.X = (base.TextRectangle.Width - sub.Width) >> 1;
if (sub.Length > 0) {
switch (line.RawString[sub.Index + sub.Length - 1]) {
case '\r':
case '\n':
sub.X += c.ITextBoxRender.GetSpaceWidth() / 2;
break;
}
}
break;
case Alignment.Right:
sub.X = base.TextRectangle.Width - sub.Width - c.ITextBoxRender.GetSpaceWidth();
if (sub.Length > 0) {
switch (line.RawString[sub.Index]) {
case '\r':
case '\n':
if (i == 0) break;
var temp = lst[i - 1];
temp.Width += sub.Width;
temp.Length += sub.Length;
temp.CharCount += 1;
lst[i - 1] = temp;
lst.RemoveAt(i);
return lst;
}
switch (line.RawString[sub.Index + sub.Length - 1]) {
case '\r':
case '\n':
sub.X += c.ITextBoxRender.GetSpaceWidth();
break;
}
break;
}
break;
}
lst[i] = sub;
}
return lst;
}
private int GetCacheByChar(TextLine line, ISTTextBoxRender render, List<SubLineInfo> lst, int nStartIndex, int nWidth) {
var c = base.Core;
int nLineWidth = nWidth, nCharWidth = 0;
int nSubStrLen = 0;
int nCharCount = 0;
int nTextViewLineWidth = base.TextRectangle.Width;
if (this.WrapAlignment != Alignment.Left) {
nTextViewLineWidth -= c.ITextBoxRender.GetSpaceWidth();
}
c.IGraphemeSplitter.Each(line.RawString, nStartIndex, (str, nStart, nLen) => {
string strChar = str.Substring(nStart, nLen);
if (c.IsEmoji(strChar)) {
nCharWidth = c.FontHeight;
} else {
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), nLineWidth);
}
if (nLineWidth + nCharWidth >= nTextViewLineWidth) {
lst.Add(new SubLineInfo() {
Index = nStartIndex,
Length = nSubStrLen,
CharCount = nCharCount,
Width = nLineWidth
});
nCharCount = 1;
nStartIndex += nSubStrLen;
nSubStrLen = nLen;
nLineWidth = nCharWidth;
} else {
nSubStrLen += nLen;
nLineWidth += nCharWidth;
nCharCount++;
}
return true;
});
lst.Add(new SubLineInfo() {
Index = nStartIndex,
Length = nSubStrLen,
CharCount = nCharCount,
Width = nLineWidth
});
return nLineWidth;
}
private List<SubLineInfo> GetCacheByWord(TextLine line, ISTTextBoxRender render) {
var c = base.Core;
int nCharCount = 0, nCharCountTemp = 0;
int nLineWidth = 0;
int nSubStrLen = 0, nIndexStart = 0;
List<SubLineInfo> lst = new List<SubLineInfo>();
int nTextViewLineWidth = base.TextRectangle.Width;
if (this.WrapAlignment != Alignment.Left) {
nTextViewLineWidth -= c.ITextBoxRender.GetSpaceWidth();
}
//if (this.Alignment == UI.STTextBox.Alignment.Justify) {
// nTextViewLineWidth -= c.ITextRender.GetSpaceWidth();
//}
c.IWordSplitter.Each(line.RawString, (str, nStart, nLen) => {
string strWord = str.Substring(nStart, nLen);
nCharCountTemp = 0;
var wi = this.GetWordInfo(line, render, strWord, nStart, nLineWidth);
if (wi.Width >= nTextViewLineWidth) {
int nCharWidth = 0;
c.IGraphemeSplitter.Each(strWord, (s, ns, nl) => {
string strChar = s.Substring(ns, nl);
if (c.IsEmoji(strChar)) {
nCharWidth = c.FontHeight;
} else {
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), nLineWidth);
}
nCharCountTemp++;
if (nLineWidth + nCharWidth >= nTextViewLineWidth) {
lst.Add(new SubLineInfo() {
Index = nIndexStart,
Length = nSubStrLen,
CharCount = nCharCount,
Width = nLineWidth
});
nIndexStart += nSubStrLen;
nSubStrLen = nl;
nLineWidth = nCharWidth;
nCharCount = nCharCountTemp;
} else {
nSubStrLen += nl;
nLineWidth += nCharWidth;
nCharCount += nCharCountTemp;
}
});
return true;
}
nCharCountTemp += wi.CharCount;
if (nLineWidth + wi.Width >= nTextViewLineWidth) {
lst.Add(new SubLineInfo() {
Index = nIndexStart,
Length = nSubStrLen,
CharCount = nCharCount,
Width = nLineWidth
});
nIndexStart += nSubStrLen;
nSubStrLen = nLen;
nLineWidth = wi.Width;
nCharCount = nCharCountTemp;
} else {
nSubStrLen += nLen;
nLineWidth += wi.Width;
nCharCount += nCharCountTemp;
}
return true;
});
lst.Add(new SubLineInfo() {
Index = nIndexStart,
Length = nSubStrLen,
CharCount = nCharCount,
Width = nLineWidth
});
return lst;
}
private WordInfo GetWordInfo(TextLine line, ISTTextBoxRender render, string strWord, int nIndex, int nLeftWidth) {
var c = base.Core;
int nWordWidth = 0;
int nCharCount = 0;
c.IGraphemeSplitter.Each(strWord, (s, ns, nl) => {
string strChar = s.Substring(ns, nl);
if (c.IsEmoji(strChar)) {
nWordWidth += c.FontHeight;
} else {
nWordWidth += c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nIndex), nLeftWidth + nWordWidth);
}
nCharCount++;
});
return new WordInfo() { Width = nWordWidth, CharCount = nCharCount };
}
public override void OnTextChanged(ISTTextBoxRender render, TextManagerTextEventArgs e) {
base.OnTextChanged(render, e);
var c = base.Core;
var m = c.TextManager;
int nIndexMin = int.MaxValue, nLineIndex = 0;
if (m.LineCount.ToString().Length != m_n_line_count_start_change.ToString().Length) {
foreach (var line in m) this.CacheLine(line, render);
m_hs_changed_temp.Clear();
nIndexMin = 0;
} else {
foreach (var v in e.TextHistoryRecord) {
if (v.Index < nIndexMin) nIndexMin = v.Index;
nLineIndex = m.GetLineIndexFromCharIndex(v.Index);
var line = m[nLineIndex];
if (m_hs_changed_temp.Contains(line)) {
this.CacheLine(line, render);
m_hs_changed_temp.Remove(line);
}
}
}
foreach (var line in m_hs_changed_temp) this.CacheLine(line, render);
nLineIndex = m.GetLineIndexFromCharIndex(nIndexMin);
for (int i = nLineIndex + 1; i < m.LineCount; i++) {
var tag_prev = _Tag(m[i - 1]);
_Tag(m[i]).ScreenLineOffset = tag_prev.ScreenLineOffset + tag_prev.SubLines.Count;
}
}
public override void OnTextStartChange(ISTTextBoxRender render, TextManagerTextEventArgs e) {
m_hs_changed_temp.Clear();
m_n_line_count_start_change = base.Core.TextManager.LineCount;
}
public override FindInfo FindFromPoint(Point pt) {
var c = base.Core;
FindInfo fi = new FindInfo();
int nXStart = base.TextRectangle.X;
float nX = 0;// nXStart - c.Scroll.XOffset;
int nIndexChar = 0, nCharWidth = 0;
int nYOffset = ((pt.Y - base.TextRectangle.Y) / c.LineHeight);
int nYValue = c.Scroll.YValue + nYOffset;
if (nYValue < 0) nYValue = 0;
int nIndexLine = this.GetLineIndexFromYScroll(nYValue);
TextLine line = c.TextManager[nIndexLine];
var tag = _Tag(line);
//SubLineInfo subLine = tag.SubLines[0];
if (nYValue >= tag.ScreenLineOffset + tag.SubLines.Count) {
nYOffset -= nYValue - tag.ScreenLineOffset - tag.SubLines.Count + 1;
}
//if (tag.ScreenLineOffset < nYValue) {
var temp = nYValue - tag.ScreenLineOffset;
if (temp >= tag.SubLines.Count) {
temp = tag.SubLines.Count - 1;
}
var subLine = tag.SubLines[temp];
//}
//nX += subLine.X;
fi.Line = line;
fi.IndexOfLine = nIndexLine;
//var nXXX = subLine.ExtraWidth * 2;
c.ITextBoxRender.BeginPaint();
c.IGraphemeSplitter.Each(line.RawString.Substring(subLine.Index, subLine.Length), nIndexChar, (str, nStart, nLen) => {
if (str[nStart] == '\r') return false;
if (str[nStart] == '\n') return false;
string strChar = str.Substring(nStart, nLen);
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), (int)nX/* - base.TextRectangle.X + c.Scroll.XOffset*/);
//nCharWidth += (int)nXXX;
if (nX + subLine.X + base.TextRectangle.X + nCharWidth > pt.X) {
fi.Find = true;
if (pt.X - base.TextRectangle.X - subLine.X - nX >= nCharWidth / 2) {
fi.IndexOfCharInLine = subLine.Index + nIndexChar + nLen;
fi.Location = new Point((int)nX + nCharWidth + base.TextRectangle.X + subLine.X, base.TextRectangle.Y + nYOffset * c.LineHeight);
} else {
fi.IndexOfCharInLine = subLine.Index + nIndexChar;
fi.Location = new Point((int)nX + base.TextRectangle.X + subLine.X, base.TextRectangle.Y + nYOffset * c.LineHeight);
}
return false;
}
nX += nCharWidth;
nIndexChar += nLen;
return true;
});
c.ITextBoxRender.EndPaint();
if (!fi.Find) {
fi.IndexOfCharInLine = subLine.Index + nIndexChar;
fi.Location = new Point((int)nX + base.TextRectangle.X + subLine.X, base.TextRectangle.Y + nYOffset * c.LineHeight);
}
fi.Find = true;
//Console.WriteLine("->>>>>>>>>>>>>>>>>>>>>" + line.RawString.Substring(subLine.Index, subLine.Length) + " -- " + fi.IndexOfChar);
return fi;
}
public override FindInfo FindFromCharIndex(int nIndex) {
var c = base.Core;
int nIndexOfLine = c.TextManager.GetLineIndexFromCharIndex(nIndex);
TextLine stLine = c.TextManager[nIndexOfLine];
if (stLine == null) {// TODO: stLine will not be null
return new FindInfo();
}
return this.FindFromCharIndex(nIndexOfLine, nIndex - stLine.IndexOfFirstChar);
}
private FindInfo FindFromCharIndex(int nIndexOfLine, int nIndex) {
var c = base.Core;
return this.FindFromCharIndex(c.ITextBoxRender, nIndexOfLine, nIndex);
}
/// <summary>
///
/// </summary>
/// <param name="g"></param>
/// <param name="stLine"></param>
/// <param name="nIndex">Index of stLine</param>
/// <returns></returns>
private FindInfo FindFromCharIndex(ISTTextBoxRender render, int nIndexOfLine, int nIndex) {
var c = base.Core;
TextLine line = c.TextManager[nIndexOfLine];
int nX = base.TextRectangle.X;
int nCharWidth = 0;
var tag = _Tag(line);
int nSubIndex = 0;
foreach (var sub in tag.SubLines) {
if (nIndex >= sub.Index && nIndex < sub.Index + sub.Length) {
break;
}
nSubIndex++;
}
var subLine = tag.SubLines[nSubIndex];
c.IGraphemeSplitter.Each(line.RawString.Substring(subLine.Index, subLine.Length), (str, nStart, nLen) => {
if (subLine.Index + nStart >= nIndex) {
return false;
}
string strChar = str.Substring(nStart, nLen);
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + subLine.Index + nStart), nX - base.TextRectangle.X + c.Scroll.XOffset);
nX += nCharWidth;
return true;
});
return new FindInfo() {
Line = line,
IndexOfLine = nIndexOfLine,
IndexOfCharInLine = nIndex,
Location = new Point((int)nX + subLine.X, base.TextRectangle.Y + (tag.ScreenLineOffset + nSubIndex - c.Scroll.YValue) * c.LineHeight)
};
}
protected override int OnDrawLine(ISTTextBoxRender render, TextLine line, int nX, int nY) {
var c = base.Core;
int nRet = 0;
int nLineSpacing = c.TextBox.GetIntYSize(c.TextBox.LineSpacing) / 2;
//nY += c.TextBox.GetIntYSize(c.TextBox.LineSpacing) / 2;
float nXStart = 0;
int nIndexEach = 0, nCharWidth;
if (string.IsNullOrEmpty(line.RawString)) {
return c.LineHeight;
}
int nCharSpacing = c.TextBox.GetIntXSize(c.TextBox.CharSpacing) / 2;
int nCurrentCharIndex = line.IndexOfFirstChar + nIndexEach;
Rectangle rect_char = new Rectangle(0, nY, 0, c.LineHeight);
var tag = _Tag(line);
var temp = tag.ScreenLineOffset < c.Scroll.YValue ? c.Scroll.YValue - tag.ScreenLineOffset : 0;
for (int i = temp; i < tag.SubLines.Count; i++) {
var subLine = tag.SubLines[i];
nXStart = nX + subLine.X;
rect_char.Y = nY;
rect_char.X = nX + subLine.X;
bool bIsEmoji = false;
TextStyleRange tsi = TextStyleRange.Empty;
c.IGraphemeSplitter.Each(line.RawString.Substring(subLine.Index, subLine.Length), nIndexEach, (str, nStart, nLen) => {
nCurrentCharIndex = line.IndexOfFirstChar + subLine.Index + nStart;
string strChar = str.Substring(nStart, nLen);
if (c.IsEmoji(strChar)) {
bIsEmoji = true;
nCharWidth = c.FontHeight;
} else {
if (nLen > 1 && strChar[nLen - 1] >= '\uFE00' && strChar[nLen - 1] <= '\uFE0F') {
strChar = str.Substring(nStart, nLen - 1);
}
bIsEmoji = false;
nCharWidth = c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), rect_char.X - subLine.X - base.TextRectangle.X) + nCharSpacing;
}
if (nXStart + nCharWidth <= base.TextRectangle.Left) {
nXStart += nCharWidth;
return true;
}
rect_char.Width = nCharWidth;
if (bIsEmoji) {
bool bSelected = nCurrentCharIndex >= c.Selection.StartIndex && nCurrentCharIndex < c.Selection.EndIndex;
c.IEmojiRender.DrawEmoji(render, strChar, rect_char.X + (nCharSpacing >> 1), nY + nLineSpacing, c.FontHeight, bSelected);
} else {
c.ITextBoxRender.DrawString(strChar, c.GetStyleFromCharIndex(nCurrentCharIndex), rect_char);
}
rect_char.X += rect_char.Width;
nXStart += nCharWidth;
if (rect_char.X >= base.TextRectangle.Right) {
return false;
}
return true;
});
nY += c.LineHeight;
nRet += c.LineHeight;
if (nY >= base.TextRectangle.Bottom) break;
}
return nRet;
}
protected override void OnDrawHead(ISTTextBoxRender render, int nStartLineIndex) {
var c = base.Core;
TextLine line = c.TextManager[nStartLineIndex];
var tag = _Tag(line);
var temp = tag.ScreenLineOffset < c.Scroll.YValue ? c.Scroll.YValue - tag.ScreenLineOffset : 0;
render.FillRectangle(base.HeadBackgroundColor, base.HeadRectangle);
var clr_temp = Color.FromArgb(base.LineNumberColor.A / 3, base.LineNumberColor);
int nY = base.HeadRectangle.Y;
this.DrawHeadLine(render, line, this.GetSubLineStatus(tag.SubLines.Count, temp), nStartLineIndex + 1, base.LineNumberColor, nY);
nY += c.LineHeight;
for (int i = temp + 1; i < tag.SubLines.Count; i++) {
if (nY >= base.HeadRectangle.Bottom) return;
this.DrawHeadLine(render, line, this.GetSubLineStatus(tag.SubLines.Count, i), nStartLineIndex + 1, clr_temp, nY);
nY += c.LineHeight;
}
for (int i = nStartLineIndex + 1; i < c.TextManager.LineCount; i++) {
line = c.TextManager[i];
tag = _Tag(line);
this.DrawHeadLine(render, line, this.GetSubLineStatus(tag.SubLines.Count, 0), i + 1, base.LineNumberColor, nY);
nY += c.LineHeight;
for (int j = 1; j < tag.SubLines.Count; j++) {
if (nY >= base.HeadRectangle.Bottom) return;
this.DrawHeadLine(render, line, this.GetSubLineStatus(tag.SubLines.Count, j), i + 1, clr_temp, nY);
nY += c.LineHeight;
}
}
}
private void DrawHeadLine(ISTTextBoxRender render, TextLine line, SubLineStatus status, int nShowNumber, Color clr, int nY) {
var c = base.Core;
//int nStatusWidth = c.TextBox.GetIntXSize(base.LineStatusWidth);
Rectangle rect_linenumber = new Rectangle(base.HeadRectangle.X, nY, base.LineNumberWidth - c.TextBox.GetIntXSize(10), c.LineHeight);
//Rectangle rect_status = new Rectangle(base.HeadRectangle.Right - nStatusWidth, nY, nStatusWidth, c.LineHeight);
Rectangle rect_temp = new Rectangle(base.HeadRectangle.X + c.TextBox.GetIntXSize(5), nY, c.TextBox.GetIntXSize(1), c.LineHeight);
if (this.ShowLineNumberGuide) {
var clr_temp = this.LineNumberGuideColor;
switch (status) {
case SubLineStatus.Start:
rect_temp.Y += c.LineHeight / 2;
rect_temp.Height -= rect_temp.Y - nY;
render.FillRectangle(clr_temp, rect_temp.Right, rect_temp.Y, rect_temp.Width * 3, rect_temp.Width);
break;
//case SubLineStatus.Middle:
case SubLineStatus.End:
rect_temp.Height -= c.LineHeight / 2;
render.FillRectangle(clr_temp, rect_temp.Right, rect_temp.Bottom - rect_temp.Width, rect_temp.Width * 3, rect_temp.Width);
break;
case SubLineStatus.None:
rect_temp.Y += rect_temp.Width;
rect_temp.Height -= rect_temp.Width * 2;
rect_temp.Width = c.TextBox.GetIntXSize(4);
clr_temp = Color.FromArgb(clr_temp.A / 3, clr_temp);
break;
}
render.FillRectangle(clr_temp, rect_temp);
}
render.DrawString(nShowNumber.ToString(), c.TextBox.Font, clr, rect_linenumber, m_sf);
//if (base.ShowLineStatus) {
// if (m_hs_changed.Contains(line)) {
// render.FillRectangle(base.LineStatusColor, rect_status);
// }
//}
}
private SubLineStatus GetSubLineStatus(int nSubLineCount, int nIndex) {
if (nSubLineCount == 1) {
return SubLineStatus.None;
} else if (nIndex == 0) {
return SubLineStatus.Start;
} else if (nIndex == nSubLineCount - 1) {
return SubLineStatus.End;
} else {
return SubLineStatus.Middle;
}
}
public override int GetLineIndexFromYScroll(int nYValue) {
var m = base.Core.TextManager;
int nLeft = 0, nRight = m.LineCount - 1, nMid = 0;
while (nLeft <= nRight) {
nMid = (nLeft + nRight) >> 1;
var tag = _Tag(m[nMid]);
if (nYValue < tag.ScreenLineOffset) {
nRight = nMid - 1;
} else if (nYValue >= tag.ScreenLineOffset + tag.SubLines.Count) {
nLeft = nMid + 1;
} else {
return nMid;
}
}
if (nMid < 0) return 0;
if (nMid >= m.LineCount) return m.LineCount - 1;
return nMid;
}
public override void SetCaretPostion(int nCharIndex) {
var c = this.Core;
int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(nCharIndex);
var line = c.TextManager[nLineIndex];
int nWidth = 0, nTempCharIndex = 0, nSubLineIndex = 0;
var tag = _Tag(line);
foreach (var v in tag.SubLines) {
nTempCharIndex = line.IndexOfFirstChar + v.Index;
if (nCharIndex >= nTempCharIndex && nCharIndex < nTempCharIndex + v.Length) {
break;
}
nSubLineIndex++;
}
if (nSubLineIndex >= tag.SubLines.Count) {
nSubLineIndex = tag.SubLines.Count - 1;
}
nTempCharIndex = nCharIndex;
var subLine = tag.SubLines[nSubLineIndex];
c.ITextBoxRender.BeginPaint();
c.IGraphemeSplitter.Each(line.RawString, subLine.Index, (str, nStart, nLen) => {
if (nStart >= nCharIndex - line.IndexOfFirstChar) return false;
string strChar = str.Substring(nStart, nLen);
nWidth += c.GetStringWidth(strChar, c.GetStyleFromCharIndex(line.IndexOfFirstChar + nStart), nWidth);
nTempCharIndex = line.IndexOfFirstChar + nStart + nLen;
return true;
});
c.ITextBoxRender.EndPaint();
c.Caret.Line = line;
c.Caret.IndexOfLine = nLineIndex;
c.Caret.IndexOfChar = nTempCharIndex;
this.SetCaretPostion((int)nWidth + this.TextRectangle.X + subLine.X, this.TextRectangle.Y + (tag.ScreenLineOffset + nSubLineIndex - c.Scroll.YValue) * c.LineHeight);
}
protected override void OnDrawLineSelectionBackground(ISTTextBoxRender render, TextLine line, int nLineIndex, STTextBoxSelectionInfo selection, int nY) {
var c = base.Core;
int nRet = 0;
//nY += c.TextBox.GetIntYSize(c.TextBox.LineSpacing) / 2;
if (string.IsNullOrEmpty(line.RawString)) {
return;
}
int nCharSpacing = c.TextBox.GetIntXSize(c.TextBox.CharSpacing) / 2;
var tag = _Tag(line);
var temp = tag.ScreenLineOffset < c.Scroll.YValue ? c.Scroll.YValue - tag.ScreenLineOffset : 0;
for (int i = temp; i < tag.SubLines.Count; i++) {
var subLine = tag.SubLines[i];
if (line.IndexOfFirstChar + subLine.Index >= selection.EndIndex) {
return;
}
if (line.IndexOfFirstChar + subLine.Index + subLine.Length <= selection.StartIndex) {
if (nY >= base.TextRectangle.Bottom) break;
nY += c.LineHeight;
nRet += c.LineHeight;
continue;
}
int nLeft = base.TextRectangle.X + subLine.X, nWidth = subLine.Width;
if (selection.StartIndex > line.IndexOfFirstChar + subLine.Index) {
nLeft = this.FindFromCharIndex(render, nLineIndex, selection.StartIndex - line.IndexOfFirstChar).Location.X;
nWidth -= nLeft - base.TextRectangle.X - subLine.X;
}
if (selection.EndIndex < line.IndexOfFirstChar + subLine.Index + subLine.Length) {
int nCurrentIndex = line.IndexOfFirstChar + subLine.Index;
nWidth = this.FindFromCharIndex(render, nLineIndex, selection.EndIndex - line.IndexOfFirstChar).Location.X;
nWidth -= nLeft;
}
render.FillRectangle(c.TextBox.SelectionColor, nLeft, nY, nWidth, c.LineHeight);
nY += c.LineHeight;
nRet += c.LineHeight;
if (nY >= base.TextRectangle.Bottom) break;
}
}
public override void OnResize(EventArgs e) {
base.OnResize(e);
var c = base.Core;
int nLineOffset = 0;
c.ITextBoxRender.BeginPaint();
foreach (TextLine line in c.TextManager) {
var tag = _Tag(line);
tag.ScreenLineOffset = nLineOffset;
tag.SubLines = this.GetCache(line, c.ITextBoxRender);
nLineOffset += tag.SubLines.Count;
}
c.ITextBoxRender.EndPaint();
//this.ResizeScroll();
//this.SetCaretPostion(c.Caret.IndexOfChar);
}
public override void OnCalcScroll(STTextBoxScrollInfo scrollInfo) {
var c = base.Core;
var m = c.TextManager;
var tag = _Tag(m[m.LineCount - 1]);
c.Scroll.MaxYValue = tag.ScreenLineOffset + tag.SubLines.Count - base.TextRectangle.Height / c.LineHeight + 2;
if (c.Scroll.MaxYValue < 0) {
c.Scroll.MaxYValue = 0;
}
if (c.Scroll.YValue > c.Scroll.MaxYValue) {
c.Scroll.YValue = c.Scroll.MaxYValue;
}
//this.SetCaretPostion(c.Caret.IndexOfChar);
}
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public interface IEmojiRender
{
bool IsEmoji(string strChar);
void DrawEmoji(ISTTextBoxRender dt, string strChar, int nX, int nY, int nWidth, bool bSelected);
}
}

View File

@ -1,94 +0,0 @@
using CPF.Controls;
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
/// <summary>
/// All drawing of STTextBox comes from this interface.
/// Calling rules:
/// STTextBox guarantees that OnBeginPaint(Graphics) or BeginPaint()
/// must be called before calling all drawing functions in this interface.
/// And call OnEndPaint(Graphics) or EndPaint() at the end of drawing.
/// During the OnPaint of the control, OnBegin/EndPaint is called for initialization.
/// Otherwise call Begin/EndPaint.
///
/// * However, if you rewrite some functions in TextView or ITextView.
/// * It needs to be called by the developer himself.
///
/// The STTextBox release uses GDI+ for rendering by default.
/// </summary>
public interface ISTTextBoxRender
{
/// <summary>
/// Bind the control
/// </summary>
/// <param name="ctrl">the STTextBox control</param>
void BindControl(Control ctrl);
void UnbindControl();
/// <summary>
/// This function will be called at the start of the STTextBox.Paint event.
/// </summary>
/// <param name="g">PaintEventArgs.Graphics</param>
void OnBeginPaint(Graphics g);
/// <summary>
/// This function will be called at the end of the STTextBox.Paint event.
/// * The destruction of [g] should not be done in this function, it should be handled by STTextBox.Paint.
/// </summary>
/// <param name="g">PaintEventArgs.Graphics</param>
void OnEndPaint(Graphics g);
/// <summary>
/// Developers should call this method instead of OnBegin(Graphics) when initializing drawing is required.
/// </summary>
void BeginPaint();
/// <summary>
/// This function corresponds to BeginPaint().
/// </summary>
void EndPaint();
/// <summary>
/// Set how many spaces are required for a tab.
/// </summary>
/// <param name="nSize">Number of spaces</param>
/// <returns>The old size</returns>
int SetTabSize(int nSize);
/// <summary>
/// Get how many spaces are required for a tab.
/// </summary>
/// <returns>Number of spaces</returns>
int GetSpaceWidth();
int GetFontHeight();
int GetTabSize();
/// <summary>
/// Get how much width the tab character needs at the current position.
/// </summary>
/// <param name="nLeftWidth">The position relative to the start of the text</param>
/// <returns>Width</returns>
int GetTabWidth(int nLeftWidth);
/// <summary>
/// How many spaces are needed to get tabs.
/// </summary>
/// <param name="nLeftWidth">The position relative to the start of the text</param>
/// <param name="nTabSize">How many spaces are required for a tab</param>
/// <returns>Space count</returns>
float GetTabSpaceCount(int nLeftWidth, int nTabSize);
/// <summary>
/// Get the string width
/// </summary>
/// <param name="strText">text</param>
/// <param name="style">Text style</param>
/// <param name="nLeftWidth">The position relative to the start of the text</param>
/// <returns>Width</returns>
int GetStringWidth(string strText, TextStyle style, int nLeftWidth);
void SetClip(Rect rect);
void ResetClip();
void DrawImage(Image img, Rect rect);
void DrawString(string strText, Font ft, CPF.Drawing.Color color, Rect rect, StringFormat sf);
void DrawString(string strText, TextStyle style, Rect rect, TextDecorationLocation Underline = TextDecorationLocation.None);
void FillRectangle(CPF.Drawing.Color backColor, Rect rect);
void FillRectangle(CPF.Drawing.Color backColor, float nX, float nY, float nWidth, float nHeight);
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public delegate void EachVoidCallBack(string strText, int nIndex, int nLen);
public delegate bool EachBoolCallBack(string strText, int nIndex, int nLen);
public interface ITextBoundary
{
List<string> Split(string strText);
int GetCount(string strText);
void Each(string strText, EachVoidCallBack callBack);
void Each(string strText, int nIndex, EachVoidCallBack callBack);
void Each(string strText, EachBoolCallBack callBack);
void Each(string strText, int nIndex, EachBoolCallBack callBack);
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public interface ITextHistory
{
void SetHistory(TextHistoryRecord[] histories);
TextHistoryRecord[] GetUndo();
TextHistoryRecord[] GetRedo();
void Clear();
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public interface ITextStyleMonitor
{
void Init(string strText);
void OnSelectionChanged(TextManager textManager, int nStart, int nLen);
void OnTextChanged(TextManager textManager, List<TextHistoryRecord> thrs);
TextStyleRange GetStyleFromCharIndex(int nIndex);
}
}

View File

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CPF.Drawing;
using CPF.Input;
namespace ST.Library.UI.STTextBox
{
public interface ITextView
{
void Init(STTextBox.Core textBoxCore);
void OnTextStartChange(ISTTextBoxRender render, TextManagerTextEventArgs e);
void OnLineChanged(ISTTextBoxRender render, TextManagerLineEventArgs e);
void OnLineRemoved(ISTTextBoxRender render, TextManagerLineEventArgs e);
void OnLineAdded(ISTTextBoxRender render, TextManagerLineEventArgs e);
void OnLineCountChanged(ISTTextBoxRender render, EventArgs e);
void OnTextChanged(ISTTextBoxRender render, TextManagerTextEventArgs e);
void OnSetCursor(MouseEventArgs e);
void OnResize(EventArgs e);
void OnDrawView(ISTTextBoxRender render);
void OnCalcTextRectangle();
void OnCalcScroll(STTextBoxScrollInfo scrollInfo);
int GetCurrentCharOffset();
Point ControlToView(Point pt);
Point ViewToControl(Point pt);
FindInfo FindFromPoint(Point pt);
FindInfo FindFromCharIndex(int nIndex);
void SetCaretPostion(int nCharIndex);
FindInfo SetCaretPostion(Point pt);
void ScrollXToMuosePoint( float nX);
void ScrollYToMousePoint(float nY);
bool ScrollToCaret();
}
}

View File

@ -1,235 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using CPF.Drawing;
using CPF;
namespace ST.Library.UI.STTextBox
{
partial class STTextBox
{
public class Core
{
private Dictionary<ITextStyleMonitor, TextStyleRange> m_dic_cache_style;
public int FontHeight { get { return this.ITextBoxRender.GetFontHeight(); } }
public int LineHeight { get { return this.ITextBoxRender.GetFontHeight() + this.TextBox.GetIntYSize(this.TextBox.LineSpacing); } }
public ITextBoundary IGraphemeSplitter { get; internal set; }
public ITextBoundary IWordSplitter { get; internal set; }
public ISTTextBoxRender ITextBoxRender { get; internal set; }
public IEmojiRender IEmojiRender { get; internal set; }
public ITextView ITextView { get; internal set; }
public ITextHistory ITextHistory { get; internal set; }
public ITextStyleMonitor[] ITextStyleMonitors { get; internal set; }
public Rect ViewRectangle { get; internal set; }
public STTextBox TextBox { get; private set; }
public TextManager TextManager { get; private set; }
public STTextBoxCaretInfo Caret { get; private set; }
public STTextBoxScrollInfo Scroll { get; private set; }
public STTextBoxSelectionInfo Selection { get; private set; }
internal Core(STTextBox textBox) {
if (textBox == null) {
throw new ArgumentNullException("textBox");
}
this.TextBox = textBox;
m_dic_cache_style = new Dictionary<ITextStyleMonitor, TextStyleRange>();
//GraphemeSplitter.CreateArrayCache();
//WordSplitter.CreateArrayCache();
this.IGraphemeSplitter = new GraphemeSplitter();
this.IWordSplitter = new WordSplitter();
this.ITextBoxRender = new STTextBoxGDIPRender();
this.ITextHistory = new TextHistory(10);
this.ITextView = new NoWrapTextView();
this.TextManager = new TextManager();
this.Caret = new STTextBoxCaretInfo();
this.Scroll = new STTextBoxScrollInfo();
this.Selection = new STTextBoxSelectionInfo();
var textManager = this.TextManager;
textManager.TextStartChange += (s, e) => {
this.ITextBoxRender.BeginPaint();
this.ITextView.OnTextStartChange(this.ITextBoxRender, e);
};
textManager.LineAdded += (s, e) => this.ITextView.OnLineAdded(this.ITextBoxRender, e);
textManager.LineChanged += (s, e) => this.ITextView.OnLineChanged(this.ITextBoxRender, e);
textManager.LineRemoved += (s, e) => this.ITextView.OnLineRemoved(this.ITextBoxRender, e);
textManager.LineCountChanged += (s, e) => {
this.ITextView.OnLineCountChanged(this.ITextBoxRender, e);
this.ITextView.OnCalcTextRectangle();
};
textManager.TextChanged += (s, e) => {
m_dic_cache_style.Clear();
if (this.ITextStyleMonitors != null) {
foreach (var m in this.ITextStyleMonitors) {
m.OnTextChanged(textManager, e.TextHistoryRecord);
}
}
this.ITextView.OnTextChanged(this.ITextBoxRender, e);
this.ITextBoxRender.EndPaint();
this.ITextView.OnCalcScroll(this.Scroll);
this.TextBox.Invalidate();
};
this.ITextBoxRender.BindControl(textBox);
this.ITextView.Init(this);
this.Selection.SelectionChanged += (s, e) => {
if (this.ITextStyleMonitors == null || this.ITextStyleMonitors.Length == 0) {
return;
}
m_dic_cache_style.Clear();
foreach (var m in this.ITextStyleMonitors) {
m.OnSelectionChanged(textManager, this.Selection.StartIndex, this.Selection.Length);
}
};
}
public ISTTextBoxRender SetTextBoxRender(ISTTextBoxRender render) {
//TODO: move out
var old = this.ITextBoxRender;
if (old == render) return old;
old.UnbindControl();
render.BindControl(this.TextBox);
this.ITextBoxRender = render;
return old;
}
public ITextStyleMonitor[] SetTextStyleMonitors(params ITextStyleMonitor[] monitors) {
var old = this.ITextStyleMonitors;
string strText = this.TextManager.GetText();
List<ITextStyleMonitor> lst = new List<ITextStyleMonitor>();
foreach (var m in monitors) {
if (m == null) {
continue;
}
lst.Add(m);
m.Init(strText);
}
this.ITextStyleMonitors = lst.ToArray();
m_dic_cache_style.Clear();
return old;
}
public bool IsEmoji(string strChar) {
if (this.IEmojiRender == null) return false;
return this.IEmojiRender.IsEmoji(strChar);
}
public int GetStringWidth(string strText, TextStyle textStyle, int nLeftWidth) {
if (this.IsEmoji(strText)) {
return this.FontHeight;
}
if (strText.Length > 1 && strText[strText.Length - 1] >= '\uFE00' && strText[strText.Length - 1] <= '\uFE0F') {
strText = strText.Substring(0, strText.Length - 1);
}
return this.ITextBoxRender.GetStringWidth(strText, textStyle, nLeftWidth) + this.TextBox.GetIntXSize(this.TextBox.CharSpacing);
}
public TextStyle GetStyleFromCharIndex(int nIndex) {
TextStyle style = new TextStyle();
if (this.ITextStyleMonitors == null || this.ITextStyleMonitors.Length == 0) {
style.ForeColor = (this.TextBox.Foreground as SolidColorFill).Color;
return style;
}
var range = TextStyleRange.Empty;
foreach (var m in this.ITextStyleMonitors) {
if (m_dic_cache_style.ContainsKey(m)) {
range = m_dic_cache_style[m];
if (nIndex >= range.Index && nIndex < range.Index + range.Length) {
if (range.Style.RejectMix) return range.Style;
style.Mix(range.Style);
continue;
}
}
range = m.GetStyleFromCharIndex(nIndex);
if (range == TextStyleRange.Empty) continue;
if (m_dic_cache_style.ContainsKey(m)) {
m_dic_cache_style[m] = range;
} else {
m_dic_cache_style.Add(m, range);
}
if (range.Style.RejectMix) return range.Style;
style.Mix(range.Style);
}
if (style.ForeColor.A == 0) {
style.ForeColor = (this.TextBox.Foreground as SolidColorFill).Color;
}
return style;
}
}
public ISTTextBoxRender SetTextBoxRender(ISTTextBoxRender render) {
if (render == null) {
throw new ArgumentNullException("render");
}
return m_core.SetTextBoxRender(render);
}
public ITextBoundary SetGraphemeSplitter(ITextBoundary textBoundary) {
if (textBoundary == null) {
throw new ArgumentNullException("textBoundary");
}
if (m_core.IGraphemeSplitter == textBoundary) {
return textBoundary;
}
var old = m_core.IGraphemeSplitter;
m_core.IGraphemeSplitter = textBoundary;
return old;
}
public ITextBoundary SetWordSplitter(ITextBoundary textBoundary) {
if (textBoundary == null) {
throw new ArgumentNullException("textBoundary");
}
if (m_core.IWordSplitter == textBoundary) {
return textBoundary;
}
var old = m_core.IWordSplitter;
m_core.IWordSplitter = textBoundary;
return old;
}
public IEmojiRender SetEmojiRender(IEmojiRender emojiRender) {
if (emojiRender == null) {
throw new ArgumentNullException("emojiRender");
}
if (m_core.IEmojiRender == emojiRender) {
return emojiRender;
}
var old = m_core.IEmojiRender;
m_core.IEmojiRender = emojiRender;
return old;
}
public ITextHistory SetTextHistory(ITextHistory textHistory) {
if (m_core.ITextHistory == textHistory) {
return textHistory;
}
var old = m_core.ITextHistory;
m_core.ITextHistory = textHistory;
return old;
}
public ITextView SetTextView(ITextView textView) {
if (textView == null) {
throw new ArgumentNullException("textView");
}
if (m_core.ITextView == textView) {
return textView;
}
var old = m_core.ITextView;
m_core.ITextView = textView;
textView.Init(m_core);
return old;
}
public ITextStyleMonitor[] SetTextStyleMonitors(params ITextStyleMonitor[] monitors) {
return m_core.SetTextStyleMonitors(monitors);
}
}
}

View File

@ -1,524 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace ST.Library.UI.STTextBox
{
public partial class STTextBox
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
switch (keyData) {
case Keys.Back:
this.ProcessBackSpaceKey();
return true;
case Keys.Tab:
this.ProcessTabKey();
return true;
case Keys.Enter:
this.ProcessEnter();
return true;
//========================================================
case Keys.Left:
this.ProcessLeftKey(false);
return true;
case Keys.Right:
this.ProcessRightKey(false);
return true;
case Keys.Up:
this.ProcessUpKey(false);
return true;
case Keys.Down:
this.ProcessDownKey(false);
return true;
case Keys.Home:
this.ProcessHomeKey(false);
return true;
case Keys.End:
this.ProcessEndKey(false);
return true;
case Keys.PageUp:
this.ProcessPageUpKey(false);
return true;
case Keys.PageDown:
this.ProcessPageDownKey(false);
return true;
//========================================================
case Keys.Shift | Keys.Tab:
this.ProcessShiftTabKey();
return true;
case Keys.Shift | Keys.Up:
this.ProcessUpKey(true);
return true;
case Keys.Shift | Keys.Down:
this.ProcessDownKey(true);
return true;
case Keys.Shift | Keys.Left:
this.ProcessLeftKey(true);
return true;
case Keys.Shift | Keys.Right:
this.ProcessRightKey(true);
return true;
case Keys.Shift | Keys.Home:
this.ProcessHomeKey(true);
return true;
case Keys.Shift | Keys.End:
this.ProcessEndKey(true);
return true;
case Keys.Shift | Keys.PageUp:
this.ProcessPageUpKey(true);
return true;
case Keys.Shift | Keys.PageDown:
this.ProcessPageDownKey(true);
return true;
//========================================================
case Keys.Control | Keys.A:
this.SelectAll();
return true;
case Keys.Control | Keys.C:
this.Copy();
return true;
case Keys.Control | Keys.X:
this.Cut();
return true;
case Keys.Control | Keys.V:
this.Paste();
return true;
case Keys.Control | Keys.Z:
this.Undo();
return true;
case Keys.Control | Keys.Y:
this.Redo();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
protected override void OnKeyPress(KeyPressEventArgs e) {
base.OnKeyPress(e);
if (e.KeyChar < 32/* || e.KeyChar > 126*/) {
return;
}
this.EnterText(e.KeyChar.ToString());
}
//==================================================================================
private void ProcessEnter() {
var c = m_core;
string strText = "\r\n";
if (this._AutoIndent) {
strText += Regex.Match(
c.TextManager[c.TextManager.GetLineIndexFromCharIndex(c.Caret.IndexOfChar)].RawString,
@"^[ \t]+" //Space,TAB
).Value;
}
this.EnterText(strText);
}
private void ProcessTabKey() {
var c = m_core;
int nIndexStartLine = 0, nIndexEndLine = 0;
if (!c.Selection.IsEmptySelection) {
nIndexStartLine = c.TextManager.GetLineIndexFromCharIndex(c.Selection.StartIndex);
nIndexEndLine = c.TextManager.GetLineIndexFromCharIndex(c.Selection.EndIndex);
}
if (nIndexStartLine == nIndexEndLine) {
if (!this._TabToSpace) {
this.EnterText("\t");
} else {
float fSpaceCount = c.ITextBoxRender.GetTabSpaceCount(c.ITextView.GetCurrentCharOffset(), this._TabSize);
this.EnterText("".PadLeft((int)Math.Ceiling(fSpaceCount)));
}
} else {
string strInsert = this._TabToSpace ? "".PadLeft(this._TabSize) : "\t";
var histories = c.TextManager.InsertAtStart(nIndexStartLine, nIndexEndLine - nIndexStartLine + 1, strInsert);
c.ITextHistory.SetHistory(histories);
var lineStart = c.TextManager[nIndexStartLine];
var lineEnd = c.TextManager[nIndexEndLine];
c.Selection.SetSelection(lineStart.IndexOfFirstChar, lineEnd.IndexOfFirstChar + lineEnd.GetLengthWithoutNewline());
c.Caret.IndexOfChar = c.Selection.EndIndex;
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
}
}
private void ProcessShiftTabKey() {
var c = m_core;
int nIndexStartLine = 0, nIndexEndLine = 0;
nIndexStartLine = c.TextManager.GetLineIndexFromCharIndex(c.Selection.StartIndex);
nIndexEndLine = c.TextManager.GetLineIndexFromCharIndex(c.Selection.EndIndex);
if (nIndexStartLine == nIndexEndLine) {
var line = c.TextManager[nIndexStartLine];
for (int i = 0; i < line.RawString.Length; i++) {
switch (line.RawString[i]) {
case ' ':
case '\t':
continue;
default:
break;
}
if (i == 0 || i + line.IndexOfFirstChar < c.Selection.StartIndex) {
return;
}
}
}
var histories = c.TextManager.TrimStartTab(nIndexStartLine, nIndexEndLine - nIndexStartLine + 1, this._TabSize);
c.ITextHistory.SetHistory(histories.ToArray());
var lineStart = c.TextManager[nIndexStartLine];
var lineEnd = c.TextManager[nIndexEndLine];
c.Selection.SetSelection(lineStart.IndexOfFirstChar, lineEnd.IndexOfFirstChar + lineEnd.GetLengthWithoutNewline());
c.Caret.IndexOfChar = c.Selection.EndIndex;
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
}
private void ProcessBackSpaceKey() {
var c = m_core;
if (c.Caret.IndexOfChar == 0 && c.Selection.IsEmptySelection) {
return;
}
if (c.Selection.IsEmptySelection) {
//c.Selection.SetIndex(c.Caret.IndexOfChar);
int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(c.Caret.IndexOfChar);
TextLine stLine = c.TextManager[nLineIndex];
if (c.Caret.IndexOfChar == stLine.IndexOfFirstChar) {//if the index is the line start index
stLine = c.TextManager[nLineIndex - 1];
//c.Selection.StartIndex -= stLine.RawString.Length - stLine.GetLengthWithoutNewline();
c.Selection.SetSelection(c.Caret.IndexOfChar, c.Caret.IndexOfChar - (stLine.RawString.Length - stLine.GetLengthWithoutNewline()));
} else {
int nIndex = stLine.IndexOfFirstChar;
c.IGraphemeSplitter.Each(stLine.RawString, (str, nStart, nLen) => {
if (nIndex + nLen >= c.Caret.IndexOfChar) {
return false;
}
nIndex += nLen;
return true;
});
//c.Selection.StartIndex = nIndex;
c.Selection.SetSelection(nIndex, c.Caret.IndexOfChar);
}
}
this.EnterText("");
}
private void ProcessUpKey(bool bShiftDown) {
var c = m_core;
if (c.Scroll.YValue == 0 && c.Caret.Y - m_core.ViewRectangle.Y < m_core.LineHeight) {
return;
}
c.Caret.Y -= c.LineHeight;// c.ITextRender.GetFontHeight();
var fi = c.ITextView.FindFromPoint(c.Caret.Location);
if (!c.Caret.CopyFromFindInfo(fi)) {
return;
}
bool bRedraw = false;
if (bShiftDown) {
c.Selection.SetSelection(c.Caret.IndexOfChar);
bRedraw = true;
} else {
if (!c.Selection.IsEmptySelection) {
bRedraw = true;
c.Caret.IndexOfChar = c.Selection.StartIndex;
}
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
if (c.ITextView.ScrollToCaret() || bRedraw) {
this.Invalidate();
}
}
private void ProcessDownKey(bool bShiftDown) {
var c = m_core;
if (c.Caret.IndexOfLine >= c.TextManager.LineCount - 1) {
//return;
}
c.Caret.Y += c.LineHeight;// c.ITextRender.GetFontHeight();
var fi = c.ITextView.FindFromPoint(c.Caret.Location);
if (!c.Caret.CopyFromFindInfo(fi)) {
return;
}
bool bRedraw = false;
if (bShiftDown) {
c.Selection.SetSelection(c.Caret.IndexOfChar);
bRedraw = true;
} else {
if (!c.Selection.IsEmptySelection) {
bRedraw = true;
c.Caret.IndexOfChar = c.Selection.EndIndex;
}
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
if (c.ITextView.ScrollToCaret() || bRedraw) {
this.Invalidate();
}
}
private void ProcessLeftKey(bool bShiftDown) {
var c = m_core;
bool bRedraw = false;
if (bShiftDown) {
var nIndex = c.TextBox.FindLeftIndex(c.Caret.IndexOfChar);
if (nIndex == c.Caret.IndexOfChar) {
return;
}
c.Caret.IndexOfChar = nIndex;
c.Selection.SetSelection(c.Caret.IndexOfChar);
bRedraw = true;
} else {
if (!c.Selection.IsEmptySelection) {
bRedraw = true;
c.Caret.IndexOfChar = c.Selection.StartIndex;
} else {
var nIndex = c.TextBox.FindLeftIndex(c.Caret.IndexOfChar);
if (nIndex == c.Caret.IndexOfChar) {
return;
}
c.Caret.IndexOfChar = nIndex;
}
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
if (c.ITextView.ScrollToCaret() || bRedraw) {
this.Invalidate();
}
}
private void ProcessRightKey(bool bShiftDown) {
var c = m_core;
bool bRedraw = false;
if (bShiftDown) {
var nIndex = c.TextBox.FindRightIndex(c.Caret.IndexOfChar);
if (nIndex == c.Caret.IndexOfChar) {
return;
}
c.Caret.IndexOfChar = nIndex;
c.Selection.SetSelection(nIndex);
bRedraw = true;
} else {
if (!c.Selection.IsEmptySelection) {
bRedraw = true;
c.Caret.IndexOfChar = c.Selection.EndIndex;
} else {
var nIndex = c.TextBox.FindRightIndex(c.Caret.IndexOfChar);
if (nIndex == c.Caret.IndexOfChar) {
return;
}
c.Caret.IndexOfChar = nIndex;
}
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
if (c.ITextView.ScrollToCaret() || bRedraw) {
this.Invalidate();
}
}
private void ProcessHomeKey(bool bShiftDown) {
var c = m_core;
bool bRedraw = false;
var stLine = c.TextManager.GetLineFromCharIndex(c.Caret.IndexOfChar);
c.Caret.IndexOfChar = stLine.IndexOfFirstChar;
if (bShiftDown) {
c.Selection.SetSelection(c.Caret.IndexOfChar);
bRedraw = true;
} else {
if (!c.Selection.IsEmptySelection) {
bRedraw = true;
}
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
if (c.ITextView.ScrollToCaret() || bRedraw) {
this.Invalidate();
}
}
private void ProcessEndKey(bool bShiftDown) {
var c = m_core;
bool bRedraw = false;
var stLine = c.TextManager.GetLineFromCharIndex(c.Caret.IndexOfChar);
//c.Caret.IndexOfChar = stLine.IndexOfFirstChar + stLine.RawString.Length;
c.Caret.IndexOfChar = stLine.IndexOfFirstChar + stLine.GetLengthWithoutNewline();
if (bShiftDown) {
c.Selection.SetSelection(c.Caret.IndexOfChar);
bRedraw = true;
} else {
if (!c.Selection.IsEmptySelection) {
bRedraw = true;
}
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
if (c.ITextView.ScrollToCaret() || bRedraw) {
this.Invalidate();
}
}
private void ProcessPageUpKey(bool bShiftDown) {
var c = m_core;
if (c.Scroll.YValue == 0) {
return;
}
int nCurrentLineCount = this.Height / c.LineHeight;
c.Scroll.YValue -= nCurrentLineCount;
if (c.Scroll.YValue < 0) {
c.Scroll.YValue = 0;
c.Caret.Y = 0;
}
var fi = c.ITextView.SetCaretPostion(c.Caret.Location);// c.ITextView.FindFromPoint(c.Caret.Location);
if (!fi.Find) {
return;
}
//c.Caret.CopyFromFindInfo(fi);
if (bShiftDown) {
c.Selection.SetSelection(c.Caret.IndexOfChar);
} else {
if (!c.Selection.IsEmptySelection) {
c.Selection.SetIndex(c.Caret.IndexOfChar);
this.Invalidate();
} else {
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
}
//c.ITextView.SetCaretPostion(c.Caret.X, c.Caret.Y);
this.Invalidate();
}
private void ProcessPageDownKey(bool bShiftDown) {
var c = m_core;
if (c.Scroll.YValue == c.Scroll.MaxYValue) {
return;
}
int nCurrentLineCount = this.Height / c.LineHeight;
c.Scroll.YValue += nCurrentLineCount;
if (c.Scroll.YValue > c.Scroll.MaxYValue) {
c.Scroll.YValue = c.Scroll.MaxYValue;
}
var fi = c.ITextView.SetCaretPostion(c.Caret.Location);// c.ITextView.FindFromPoint(c.Caret.Location);
if (!fi.Find) {
return;
}
//c.Caret.CopyFromFindInfo(fi);
if (bShiftDown) {
c.Selection.SetSelection(c.Caret.IndexOfChar);
} else {
if (!c.Selection.IsEmptySelection) {
c.Selection.SetIndex(c.Caret.IndexOfChar);
this.Invalidate();
} else {
c.Selection.SetIndex(c.Caret.IndexOfChar);
}
}
//c.ITextView.SetCaretPostion(c.Caret.X, c.Caret.Y);
this.Invalidate();
}
private void EnterText(string strText) {
var c = m_core;
var history = c.TextManager.SetText(c.Selection.StartIndex, c.Selection.Length, strText);
if (history != TextHistoryRecord.Empty) {
c.ITextHistory.SetHistory(new TextHistoryRecord[] { history });
}
c.Caret.IndexOfChar = c.Selection.StartIndex + strText.Length;
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
c.Selection.SetIndex(c.Caret.IndexOfChar);
c.ITextView.ScrollToCaret();
//this.Invalidate();
}
//==================================================
private int FindRightIndex(int nIndex) {
var c = m_core;
if (nIndex >= c.TextManager.TextLength) {
return c.TextManager.TextLength;
}
int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(nIndex);
var line = c.TextManager[nLineIndex];
c.IGraphemeSplitter.Each(line.RawString, nIndex - line.IndexOfFirstChar, (str, nStart, nLen) => {
nIndex += nLen;
return false;
});
return nIndex;
}
//private FindInfo FindRightChar(int nIndex) {
// //TODO: add location for return;
// var c = m_core;
// if (nIndex >= c.TextManager.TextLength) {
// return FindInfo.Empty;
// }
// int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(nIndex);
// var line = c.TextManager[nLineIndex];
// c.IGraphemeSplitter.Each(line.RawString, nIndex - line.IndexOfFirstChar, (str, nStart, nLen) => {
// nIndex += nLen;
// return false;
// });
// return new FindInfo() {
// Find = true,
// Line = line,
// IndexOfCharInLine = nIndex - line.IndexOfFirstChar,
// IndexOfLine = nLineIndex,
// };
//}
public int FindLeftIndex(int nIndex) {
var c = m_core;
if (nIndex <= 1) return 0;
int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(nIndex);
TextLine line = c.TextManager[nLineIndex];
if (nIndex == line.IndexOfFirstChar) {
line = c.TextManager[--nLineIndex];
if (line.RawString.Length > 1 && line.RawString[line.RawString.Length - 2] == '\r') {
nIndex -= 2;
} else {
nIndex -= 1;
}
} else {
int nIndexRet = line.IndexOfFirstChar;
c.IGraphemeSplitter.Each(line.RawString, (str, nStart, nLen) => {
if (nIndexRet + nLen >= nIndex) {
return false;
}
nIndexRet += nLen;
return true;
});
nIndex = nIndexRet;
}
return nIndex;
}
//private FindInfo FindLeftChar(int nIndex) {
// //TODO: add location for return;
// var c = m_core;
// if (nIndex <= 1) return new FindInfo() {
// Find = true,
// Line = c.TextManager[0]
// };
// int nLineIndex = c.TextManager.GetLineIndexFromCharIndex(nIndex);
// TextLine line = c.TextManager[nLineIndex];
// if (nIndex == line.IndexOfFirstChar) {
// line = c.TextManager[--nLineIndex];
// if (line.RawString.Length > 1 && line.RawString[line.RawString.Length - 2] == '\r') {
// nIndex -= 2;
// } else {
// nIndex -= 1;
// }
// } else {
// int nIndexRet = line.IndexOfFirstChar;
// c.IGraphemeSplitter.Each(line.RawString, (str, nStart, nLen) => {
// if (nIndexRet + nLen >= nIndex) {
// return false;
// }
// nIndexRet += nLen;
// return true;
// });
// nIndex = nIndexRet;
// }
// return new FindInfo() {
// Find = true,
// Line = line,
// IndexOfCharInLine = nIndex - line.IndexOfFirstChar,
// IndexOfLine = nLineIndex
// };
//}
}
}

View File

@ -1,245 +0,0 @@
using CPF;
using CPF.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
partial class STTextBox
{
private struct ScrollIncrement
{
public int Time;
public int Value;
public ScrollIncrement(int nTime, int nValue) {
this.Time = nTime;
this.Value = nValue;
}
}
private DateTime m_dt_last_scroll_h = DateTime.Now;
private DateTime m_dt_last_scroll_v = DateTime.Now;
private ScrollIncrement[] m_arr_si = new ScrollIncrement[]{
new ScrollIncrement(20, 6),
new ScrollIncrement(30, 5),
new ScrollIncrement(40, 4),
new ScrollIncrement(50, 3),
new ScrollIncrement(60, 2),
};
protected override void OnMouseDown(MouseButtonEventArgs e) {
base.OnMouseDown(e);
var c = m_core;
this.Focus();//设置焦点
if (c.Scroll.HoverScrollBar != STTextBoxScrollInfo.ScrollBarType.None) {
if (c.Scroll.HBackRect.Contains(e.Location)) {
c.Scroll.DownScrollBar = STTextBoxScrollInfo.ScrollBarType.H;
c.ITextView.ScrollXToMuosePoint(e.Location.X);
this.Invalidate();
} else if (c.Scroll.VBackRect.Contains(e.Location)) {
c.Scroll.DownScrollBar = STTextBoxScrollInfo.ScrollBarType.V;
c.ITextView.ScrollYToMousePoint(e.Location.Y);
this.Invalidate();
}
return;
}
var fi = c.ITextView.SetCaretPostion(e.Location);// c.ITextView.FindFromPoint(e.Location);
//c.Caret.CopyFromFindInfo(fi);
var key = Root.InputManager.KeyboardDevice.Modifiers;
if (key != InputModifiers.Shift) {
c.Selection.SetIndex(c.Caret.IndexOfChar);
} else {
//if (c.Caret.IndexOfChar < c.Selection.AnchorIndex) {
// //c.Selection.StartIndex = c.Caret.IndexOfChar;
// //c.Selection.EndIndex = c.Selection.AnchorIndex;
// c.Selection.SetSelection(c.Selection.AnchorIndex, c.Caret.IndexOfChar);
//} else {
// c.Selection.StartIndex = c.Selection.AnchorIndex;
// c.Selection.EndIndex = c.Caret.IndexOfChar;
//}
c.Selection.SetSelection(c.Selection.AnchorIndex, c.Caret.IndexOfChar);
}
//c.ITextView.SetCaretPostion(c.Caret.X, c.Caret.Y);
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e) {
base.OnMouseMove(e);
var c = m_core;
switch (c.Scroll.DownScrollBar) {
case STTextBoxScrollInfo.ScrollBarType.V:
c.ITextView.ScrollYToMousePoint(e.Location.Y);
this.Invalidate();
return;
case STTextBoxScrollInfo.ScrollBarType.H:
c.ITextView.ScrollXToMuosePoint(e.Location.X);
this.Invalidate();
return;
}
if (e.LeftButton == MouseButtonState.Pressed) {
//var sw = new System.Diagnostics.Stopwatch();
//sw.Start();
var fi = c.ITextView.FindFromPoint(e.Location);
if (!fi.Find) return;
c.Caret.CopyFromFindInfo(fi);
int nIndex = c.Caret.IndexOfChar;
//if (nIndex > c.Selection.AnchorIndex) {
// c.Selection.SetSelection(c.Selection.AnchorIndex, nIndex);
// //c.Selection.StartIndex = c.Selection.AnchorIndex;
// //c.Selection.EndIndex = nIndex;
//} else {
// c.Selection.SetSelection(nIndex, c.Selection.AnchorIndex);
// //c.Selection.StartIndex = nIndex;
// //c.Selection.EndIndex = c.Selection.AnchorIndex;
//}
c.Selection.SetSelection(c.Selection.AnchorIndex, nIndex);
c.ITextView.SetCaretPostion(fi.IndexOfChar);
c.ITextView.ScrollToCaret();
//sw.Stop();
//Console.WriteLine("CheckSelection: - " + sw.ElapsedMilliseconds);
this.Invalidate();
return;
}
//没有鼠标点击
if (e.LeftButton == MouseButtonState.Released&& e.RightButton == MouseButtonState.Released && c.Scroll.CountDown != 0) {
if (c.Scroll.VBackRect.Contains(e.Location)) {
c.Scroll.HoverScrollBar = STTextBoxScrollInfo.ScrollBarType.V;
} else if (c.Scroll.HBackRect.Contains(e.Location)) {
c.Scroll.HoverScrollBar = STTextBoxScrollInfo.ScrollBarType.H;
} else {
c.Scroll.HoverScrollBar = STTextBoxScrollInfo.ScrollBarType.None;
}
if (c.Scroll.HoverScrollBar != STTextBoxScrollInfo.ScrollBarType.None) {
this.ShowScrollBar(c.Scroll.DisplayTime);
if (this.SetCursor(Cursors.Arrow)) {
this.Invalidate();
}
} else {
if (this.SetCursor(Cursors.Ibeam)) {
this.Invalidate();
}
}
} else {
c.ITextView.OnSetCursor(e);
}
}
protected override void OnMouseUp(MouseButtonEventArgs e) {
base.OnMouseUp(e);
var c = m_core;
c.Scroll.DownScrollBar = STTextBoxScrollInfo.ScrollBarType.None;
this.Invalidate();
}
protected override void OnMouseLeave(MouseEventArgs e) {
base.OnMouseLeave(e);
var c = m_core;
c.Scroll.HoverScrollBar = STTextBoxScrollInfo.ScrollBarType.None;
}
protected override void OnMouseWheel(MouseWheelEventArgs e) {
base.OnMouseWheel(e);
DateTime dt_now = DateTime.Now;
//Console.WriteLine("Scroll: --------------------- " + dt_now.Subtract(m_dt_last_scroll_v).TotalMilliseconds);
int nIncrement = 1;
int nTemp = (int)dt_now.Subtract(m_dt_last_scroll_v).TotalMilliseconds;
foreach (var v in m_arr_si) {
if (nTemp < v.Time) {
nIncrement = v.Value;
break;
}
}
m_dt_last_scroll_v = dt_now;
var c = m_core;
if (e.Delta.Length > 0) {//应该是滚动距离判断
if (c.Scroll.YValue <= 0) return;
if (c.Scroll.YValue - nIncrement < 0) {
nIncrement = c.Scroll.YValue;
}
c.Scroll.YValue -= nIncrement;
c.Caret.Y += nIncrement * c.LineHeight;// this.Font.Height;
} else {
if (c.Scroll.YValue >= c.Scroll.MaxYValue) {
return;
}
if (c.Scroll.YValue + nIncrement > c.Scroll.MaxYValue) {
nIncrement = c.Scroll.MaxYValue - c.Scroll.YValue;
}
c.Scroll.YValue += nIncrement;
c.Caret.Y -= c.LineHeight * nIncrement;// c.ITextRender.GetFontHeight();
}
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
//c.ITextView.SetCaretPostion(c.Caret.X, c.Caret.Y);
this.ShowScrollBar(c.Scroll.DisplayTime);
this.Invalidate();
//c.Scroll.Timer = 5;
}
/*protected virtual void OnMouseHWheel(MouseEventArgs e) {
DateTime dt_now = DateTime.Now;
//Console.WriteLine("Scroll: --------------------- " + dt_now.Subtract(m_dt_last_scroll_h).TotalMilliseconds);
int nIncrement = 1;
int nTemp = (int)dt_now.Subtract(m_dt_last_scroll_h).TotalMilliseconds;
foreach (var v in m_arr_si) {
if (nTemp < v.Time) {
nIncrement = v.Value;
break;
}
}
m_dt_last_scroll_h = dt_now;
var c = m_core;
if (e.Delta < 0) {
if (c.Scroll.XValue <= 0) return;
if (c.Scroll.XValue - nIncrement < 0) {
nIncrement = c.Scroll.XValue;
}
c.Scroll.XValue -= nIncrement;
c.Caret.X += c.Scroll.XIncrement * nIncrement;
} else {
if (c.Scroll.XValue >= c.Scroll.MaxXValue) {
return;
}
if (c.Scroll.XValue + nIncrement > c.Scroll.MaxXValue) {
nIncrement = c.Scroll.MaxXValue - c.Scroll.XValue;
}
c.Scroll.XValue += nIncrement;
c.Caret.X -= c.Scroll.XIncrement * nIncrement;
}
//c.ITextView.SetCaretPostion(c.Caret.X, c.Caret.Y);
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
this.ShowScrollBar(c.Scroll.DisplayTime);
this.Invalidate();
//c.Scroll.Timer = 5;
}*/
protected override void OnDoubleClick(RoutedEventArgs e)
{
base.OnDoubleClick(e);
var c = m_core;
var fi = c.ITextView.FindFromPoint(e.Location);
int nIndex = fi.IndexOfChar - fi.Line.IndexOfFirstChar;
int nSelectionStart = fi.IndexOfChar, nSelectionLen = 0;
c.IWordSplitter.Each(fi.Line.RawString, (str, nStart, nLen) => {
if (nIndex >= nStart && nIndex < nStart + nLen)
{
switch (str[nStart])
{
case '\r':
case '\n':
return false;
}
nSelectionStart = fi.Line.IndexOfFirstChar + nStart;
nSelectionLen = nLen;
return false;
}
nSelectionStart = fi.Line.IndexOfFirstChar + nStart;
nSelectionLen = nLen;
return true;
});
c.Selection.SetSelection(nSelectionStart, nSelectionStart + nSelectionLen);
c.Caret.IndexOfChar = c.Selection.EndIndex;
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
this.Invalidate();
}
}
}

View File

@ -1,497 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using CPF.Controls;
using CPF.Drawing;
using System.Timers;
using CPF;
using CPF.Input;
namespace ST.Library.UI.STTextBox
{
public partial class STTextBox : Control
{
//var dpi = Root.LayoutScaling;
public Font Font {
set {
this.FontFamily = value.FontFamily;
this.FontSize = value.FontSize;
this.FontStyle = value.FontStyle;
}
get {
return new Font(this.FontFamily, this.FontSize, this.FontStyle);
}
}
public float DPIZoom { get { return Root.RenderScaling; } }
private int _BorderWidth = 1;
public int BorderWidth {
get { return _BorderWidth; }
set { _BorderWidth = value; }
}
private int _LineSpacing = 0;
public int LineSpacing {
get { return _LineSpacing; }
set {
if (value < 0) {
throw new ArgumentException("The value must be more than zero");
}
_LineSpacing = value;
this.Invalidate();
}
}
private int _CharSpacing = 0;
public int CharSpacing {
get { return _CharSpacing; }
set {
if (value < 0) {
throw new ArgumentException("The value must be more than zero");
}
_CharSpacing = value;
this.Invalidate();
}
}
private Color _BorderColor = Color.FromArgb(125, 0, 0, 0);
public Color BorderColor {
get { return _BorderColor; }
set {
if (_BorderColor == value) {
return;
}
_BorderColor = value;
this.Invalidate();
}
}
private Color _SelectionColor = Color.FromArgb(125, Color.DarkGray.R, Color.DarkGray.G, Color.DarkGray.B);
public Color SelectionColor {
get { return _SelectionColor; }
set {
if (value == _SelectionColor) {
return;
}
_SelectionColor = value;
if (!m_core.Selection.IsEmptySelection) {
this.Invalidate();
}
}
}
private bool _AllowScrollBar = true;
public bool AllowScrollBar {
get { return _AllowScrollBar; }
set { _AllowScrollBar = value; }
}
private Color _ScrollbarBackColor = Color.FromArgb(40, Color.Gray.R, Color.Gray.G, Color.Gray.B);
public Color ScrollbarBackColor {
get { return _ScrollbarBackColor; }
set { _ScrollbarBackColor = value; }
}
private Color _ScrollBarCornerColor =Color.FromArgb(80, Color.Gray.R, Color.Gray.G, Color.Gray.B);
public Color ScrollBarCornerColor {
get { return _ScrollBarCornerColor; }
set { _ScrollBarCornerColor = value; }
}
private Color _ScrollbarThumbHoverColor = Color.FromArgb(80, Color.Gray.R, Color.Gray.G, Color.Gray.B);
public Color ScrollbarThumbHoverColor {
get { return _ScrollbarThumbHoverColor; }
set { _ScrollbarThumbHoverColor = value; }
}
private Color _ScrollbarThumbBackColor = Color.FromArgb(80, Color.Black.R, Color.Black.G, Color.Black.B);
public Color ScrollbarThumbBackColor {
get { return _ScrollbarThumbBackColor; }
set { _ScrollbarThumbBackColor = value; }
}
private int _TabSize = 4;
private bool _AutoIndent = true;
private bool _TabToSpace = false;
private const int WM_MOUSEHWHEEL = 0x020E;
private object m_obj_sync = new object();
private Timer m_timer;
private IntPtr m_hIMC;
protected Core m_core;
public STTextBox() {
//this.SetStyle(ControlStyles.UserPaint, true);
//this.SetStyle(ControlStyles.ResizeRedraw, true);
//this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
//this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.Background = Color.White;
m_timer = new Timer();
m_timer.Interval = 1000;
m_timer.Elapsed += m_timer_Tick;
m_core = new Core(this);
}
#region override
protected override void OnRender(DrawingContext e) {
base.OnRender(e);
//System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
//sw.Start();
var render = m_core.ITextBoxRender;
//try {
render.OnBeginPaint(new Graphics(e));
m_core.ITextView.OnDrawView(render);
if (this._AllowScrollBar && m_core.Scroll.CountDown != 0) {
this.OnCalcScrollRectangle(m_core.Scroll);
bool bFlag = true;
if (m_core.Scroll.HBackRect != m_core.Scroll.HThumbRect) {
this.OnDrawHScrollBar(render, m_core.Scroll);
} else { bFlag = false; }
if (m_core.Scroll.VBackRect != m_core.Scroll.VThumbRect) {
this.OnDrawVScrollBar(render, m_core.Scroll);
} else { bFlag = false; }
if (bFlag) this.OnDrawScrollBarCorner(render, m_core.Scroll);
}
this.OnDrawBorder(render);
render.OnEndPaint(new Graphics(e));
//} catch (Exception ex) {
// MessageBox.Show(ex.Message + "\r\n\r\n" + ex.StackTrace);
//}
//sw.Stop();
//Console.WriteLine("OnPaint - " + sw.ElapsedMilliseconds + "ms");
}
protected virtual void OnDrawBorder(ISTTextBoxRender render) {
if (this._BorderWidth <= 0) {
return;
}
int nWidth = this.GetIntXSize(this._BorderWidth);
int nHeight = this.GetIntYSize(this._BorderWidth);
if (nWidth == 0) nWidth = 1;
if (nHeight == 0) nHeight = 1;
render.FillRectangle(this._BorderColor, 0, 0, nWidth, this.Height.Value);
render.FillRectangle(this._BorderColor, this.Width.Value - nWidth, 0, nWidth, this.Height.Value);
render.FillRectangle(this._BorderColor, nWidth, 0, this.Width.Value - nWidth * 2, nHeight);
render.FillRectangle(this._BorderColor, nWidth, this.Height.Value - nHeight, this.Width.Value - nWidth * 2, nHeight);
}
/*protected override void OnResize(EventArgs e) {
base.OnResize(e);
int nX = this.GetIntXSize(this._BorderWidth);
int nY = this.GetIntYSize(this._BorderWidth);
var rect = new Rect(nX, nY, this.Width.Value - nX * 2, this.Height.Value - nY * 2);
if (rect.Height < 1 || rect.Width < 1 || rect == m_core.ViewRectangle) {
return;
}
m_core.ViewRectangle = rect;
m_core.ITextView.OnCalcTextRectangle();
m_core.ITextView.OnResize(e);
m_core.ITextView.OnCalcScroll(m_core.Scroll);
}*/
protected override void OnLayoutUpdated()
{
base.OnLayoutUpdated();
int nX = this.GetIntXSize(this._BorderWidth);
int nY = this.GetIntYSize(this._BorderWidth);
var rect = new Rect(nX, nY, this.Width.Value - nX * 2, this.Height.Value - nY * 2);
if (rect.Height < 1 || rect.Width < 1 || rect == m_core.ViewRectangle)
{
return;
}
m_core.ViewRectangle = rect;
m_core.ITextView.OnCalcTextRectangle();
m_core.ITextView.OnResize(null);//hmbb
m_core.ITextView.OnCalcScroll(m_core.Scroll);
}
//hmbb 光标 暂时先不用
/*protected override void OnGotFocus(GotFocusEventArgs e) {
base.OnGotFocus(e);
Win32.CreateCaret(this.Handle, IntPtr.Zero, this.GetIntXSize(1), m_core.LineHeight);
Win32.ShowCaret(this.Handle);
}
protected override void OnLostFocus(EventArgs e) {
base.OnLostFocus(e);
Win32.HideCaret(this.Handle);
Win32.DestroyCaret();
}*/
#endregion
#region public
public float GetFloatXSize(int nSize) { return nSize * this.DPIZoom; }
public float GetFloatXSize(float fSize) { return fSize * this.DPIZoom; }
public int GetIntXSize(int nSize) { return (int)Math.Round(nSize * this.DPIZoom); }
public int GetIntXSize(float fSize) { return (int)Math.Round(fSize * this.DPIZoom); }
public float GetFloatYSize(int nSize) { return nSize * this.DPIZoom; }
public float GetFloatYSize(float fSize) { return fSize * this.DPIZoom; }
public int GetIntYSize(int nSize) { return (int)Math.Round(nSize * this.DPIZoom); }
public int GetIntYSize(float fSize) { return (int)Math.Round(fSize * this.DPIZoom); }
public void ShowScrollBar(int nSecond) {
lock (m_obj_sync) {
m_core.Scroll.CountDown = nSecond;
}
m_timer.Start();
}
public TextHistoryRecord SetText(string strText) {
return m_core.TextManager.SetText(strText);
}
public TextHistoryRecord SetText(int nIndex, string strText) {
return m_core.TextManager.SetText(nIndex, strText);
}
public TextHistoryRecord SetText(int nIndex, int nLen, string strText) {
return m_core.TextManager.SetText(nIndex, nLen, strText);
}
public void SelectAll() {
m_core.Selection.SetSelection(0, m_core.TextManager.TextLength);
m_core.Caret.IndexOfChar = m_core.Selection.EndIndex;
m_core.ITextView.SetCaretPostion(m_core.Caret.IndexOfChar);
this.Invalidate();
}
public void Copy() {
this.Copy(false);
}
public void Cut() {
this.Copy(true);
}
private void Copy(bool bCut) {
var c = m_core;
if (c.Selection.IsEmptySelection) {
return;
}
var data = c.TextManager.GetText(c.Selection.StartIndex, c.Selection.Length);
Clipboard.SetData((DataFormat.Text, data));
if (bCut) {
this.EnterText("");
}
}
public void Paste() {
string strText = Clipboard.GetData(DataFormat.Text).ToString();
if (string.IsNullOrEmpty(strText)) {
return;
}
this.EnterText(strText);
}
public void Undo() {
this.RunHistory(true);
}
public void Redo() {
this.RunHistory(false);
}
private void RunHistory(bool isUndo) {
var c = m_core;
if (c.ITextHistory == null) {
return;
}
var histories = isUndo ? c.ITextHistory.GetUndo() : c.ITextHistory.GetRedo();
if (histories == null || histories.Length == 0) {
return;
}
if (isUndo) {
var temp = new TextHistoryRecord[histories.Length];
for (int i = 0; i < histories.Length; i++) {
temp[i] = histories[i];
temp[i].NewText = histories[i].OldText;
temp[i].OldText = histories[i].NewText;
}
histories = temp;
}
histories = c.TextManager.RunHistory(histories);
var last = histories[histories.Length - 1];
c.Selection.SetSelection(last.Index, last.Index + last.NewText.Length);
c.Caret.IndexOfChar = m_core.Selection.EndIndex;
c.ITextView.SetCaretPostion(c.Caret.IndexOfChar);
c.ITextView.ScrollToCaret();
this.Invalidate();
}
#endregion
#region protected
protected virtual void OnImeStart(IntPtr hIMC) { }
protected virtual void OnImeResultStr(IntPtr hIMC, string strResult) { this.EnterText(strResult); }
protected virtual void OnImeCompStr(IntPtr hIMC, string strComp) { }
protected virtual void OnImeEnd(IntPtr hIMC) { }
protected virtual void OnCalcScrollRectangle(STTextBoxScrollInfo scroll) {
int nSW = this.GetIntXSize(scroll.Size);
int nSH = this.GetIntYSize(scroll.Size);
var c = m_core;
Rect rectV = c.ViewRectangle;
scroll.HBackRect = new Rect(rectV.X, rectV.Bottom - nSH, rectV.Width - nSW, nSH);
scroll.VBackRect = new Rect(rectV.Right - nSW, rectV.Y, nSW, rectV.Height - nSH);
Rect rect_h_thumb = scroll.HBackRect;
Rect rect_v_thumb = scroll.VBackRect;
float fScale = ((float)rectV.Width / scroll.XIncrement) / (rectV.Width / scroll.XIncrement + scroll.MaxXValue);
rect_h_thumb.Width = (int)(rectV.Width * fScale);
if (rect_h_thumb.Width > scroll.HBackRect.Width) {
rect_h_thumb.Width = scroll.HBackRect.Width;
} else if (rect_h_thumb.Width < this.GetIntXSize(4)) {
rect_h_thumb.Width = this.GetIntXSize(4);
}
fScale = ((float)rectV.Height / c.LineHeight) / (rectV.Height / c.LineHeight + scroll.MaxYValue);
rect_v_thumb.Height = (int)(rectV.Height * fScale);
if (rect_v_thumb.Height > scroll.VBackRect.Height) {
rect_v_thumb.Height = scroll.VBackRect.Height;
} else if (rect_v_thumb.Height < this.GetIntYSize(4)) {
rect_v_thumb.Height = this.GetIntYSize(4);
}
rect_h_thumb.X = rectV.X;
if (scroll.MaxXValue > 0) {
fScale = (float)scroll.XValue / scroll.MaxXValue;
rect_h_thumb.X += (int)((scroll.HBackRect.Width - rect_h_thumb.Width) * fScale);
}
rect_v_thumb.Y = rectV.Y;
if (scroll.MaxYValue > 0) {
fScale = (float)scroll.YValue / scroll.MaxYValue;
rect_v_thumb.Y += (int)((scroll.VBackRect.Height - rect_v_thumb.Height) * fScale);
}
scroll.HThumbRect = rect_h_thumb;
scroll.VThumbRect = rect_v_thumb;
if (scroll.VBackRect == rect_v_thumb) {
rect_h_thumb.Width += nSW;
scroll.HThumbRect = rect_h_thumb;
var temp = scroll.HBackRect;
temp.Width += nSW;
scroll.HBackRect = temp;
} else if (scroll.HBackRect == rect_h_thumb) {
rect_v_thumb.Height += nSH;
scroll.VThumbRect = rect_v_thumb;
var temp = scroll.VBackRect;
temp.Height += nSH;
scroll.VBackRect = temp;
} else {
}
//scroll.HThumbRect = rect_h_thumb;
//scroll.VThumbRect = rect_v_thumb;
}
protected virtual void OnDrawVScrollBar(ISTTextBoxRender render, STTextBoxScrollInfo scroll) {
var clr = scroll.HoverScrollBar == STTextBoxScrollInfo.ScrollBarType.V ? this._ScrollbarThumbHoverColor : this._ScrollbarBackColor;
render.FillRectangle(clr, scroll.VBackRect);
render.FillRectangle(clr, scroll.VBackRect.X, scroll.VBackRect.Y, this.GetIntXSize(1), scroll.VBackRect.Height);
render.FillRectangle(this._ScrollbarThumbBackColor, scroll.VThumbRect);
}
protected virtual void OnDrawHScrollBar(ISTTextBoxRender render, STTextBoxScrollInfo scroll) {
var clr = scroll.HoverScrollBar == STTextBoxScrollInfo.ScrollBarType.H ? this._ScrollbarThumbHoverColor : this._ScrollbarBackColor;
render.FillRectangle(clr, scroll.HBackRect);
render.FillRectangle(clr, scroll.HBackRect.X, scroll.HBackRect.Y, scroll.HBackRect.Width, this.GetIntYSize(1));
render.FillRectangle(this._ScrollbarThumbBackColor, scroll.HThumbRect);
}
protected virtual void OnDrawScrollBarCorner(ISTTextBoxRender render, STTextBoxScrollInfo scroll) {
int nWidth = this.GetIntXSize(scroll.Size);
int nHeight = this.GetIntYSize(scroll.Size);
render.FillRectangle(
this._ScrollBarCornerColor, m_core.ViewRectangle.Right - nWidth,
m_core.ViewRectangle.Bottom - nHeight,
nWidth,
nHeight);
}
#endregion
#region private
private bool SetCursor(Cursor c) {
if (this.Cursor == c) {
return false;
}
this.Cursor = c;
return true;
}
//hmbb 输入法获取输入
/*private void OnImeStartPrivate(IntPtr hIMC) {
var CandidateForm = new Win32.CANDIDATEFORM() {
dwStyle = Win32.CFS_CANDIDATEPOS,
ptCurrentPos = m_core.Caret.Location
};
Win32.ImmSetCandidateWindow(hIMC, ref CandidateForm);
var CompositionForm = new Win32.COMPOSITIONFORM() {
dwStyle = Win32.CFS_FORCE_POSITION,
ptCurrentPos = m_core.Caret.Location
};
Win32.ImmSetCompositionWindow(hIMC, ref CompositionForm);
var logFont = new Win32.LOGFONT() {
lfHeight = m_core.FontHeight,
lfFaceName = this.Font.FontFamily + "\0"
};
Win32.ImmSetCompositionFont(hIMC, ref logFont);
this.OnImeStart(hIMC);
}
private void OnImeEndPrivate(IntPtr hIMC) {
Win32.ImmReleaseContext(this.Handle, hIMC);
this.OnImeEnd(hIMC);
}
private void OnImeResultStrPrivate(IntPtr hIMC, string strResult) {
var CompositionForm = new Win32.COMPOSITIONFORM() {
dwStyle = Win32.CFS_FORCE_POSITION,
ptCurrentPos = m_core.Caret.Location
};
Win32.ImmSetCompositionWindow(hIMC, ref CompositionForm);
this.OnImeResultStr(hIMC, strResult);
}*/
private void m_timer_Tick(object sender, EventArgs e) {
if (m_core.Scroll.HoverScrollBar != STTextBoxScrollInfo.ScrollBarType.None) {
return;
}
lock (m_obj_sync) {
m_core.Scroll.CountDown--;
}
if (m_core.Scroll.CountDown <= 0) {
m_timer.Stop();
this.Invalidate();
}
//设置输入法位置
var point = m_core.Caret.Location;
var p = this.PointToView(point);
Root?.ViewImpl.SetIMEPosition(p);
}
#endregion
}
}

View File

@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public delegate void TextManagerTextEventHandler(object sender, TextManagerTextEventArgs e);
public delegate void TextManagerLineEventHandler(object sender, TextManagerLineEventArgs e);
public class TextManagerTextEventArgs : EventArgs
{
public List<TextHistoryRecord> TextHistoryRecord { get; private set; }
public TextManagerTextEventArgs(List<TextHistoryRecord> thrs) {
this.TextHistoryRecord = thrs;
}
}
public class TextManagerLineEventArgs : EventArgs
{
public int IndexOfLine { get; private set; }
public TextLine Line { get; private set; }
public TextHistoryRecord History { get; private set; }
public TextManagerLineEventArgs(int nLineIndex, TextLine stLine, TextHistoryRecord history) {
this.IndexOfLine = nLineIndex;
this.History = history;
this.Line = stLine;
}
}
}

View File

@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public struct TextHistoryRecord
{
public int Index;
public string OldText;
public string NewText;
public static TextHistoryRecord Empty;
public override string ToString() {
return "[" + Index + "," + OldText + "," + NewText + "]";
}
public static bool operator ==(TextHistoryRecord a, TextHistoryRecord b) {
if (a.Index != b.Index) return false;
if (a.OldText != b.OldText) return false;
if (a.NewText != b.NewText) return false;
return true;
}
public static bool operator !=(TextHistoryRecord a, TextHistoryRecord b) {
return !(a == b);
}
public override bool Equals(object obj) {
return base.Equals(obj);
}
public override int GetHashCode() {
return base.GetHashCode();
}
}
}

View File

@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ST.Library.UI.STTextBox
{
public class TextLine
{
public int IndexOfFirstChar { get; internal set; }
public string RawString { get; internal set; }
public object Tag { get; set; }
internal TextLine() {
this.RawString = string.Empty;
}
public int GetLengthWithoutNewline() {
for (int i = this.RawString.Length - 1; i >= 0; i--) {
switch (this.RawString[i]) {
case '\r':
case '\n':
continue;
default:
return i + 1;
}
}
return 0;
}
public override string ToString() {
return "[" + IndexOfFirstChar + "]" + this.RawString;
}
}
}

View File

@ -1,454 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace ST.Library.UI.STTextBox
{
public class TextManager : IEnumerable<TextLine>
{
public int LineCount {
get { return m_nLineCount; }
}
public int TextLength {
get { return m_nTextLength; }
}
public TextLine this[int nIndex] {
get {
if (nIndex < 0 || nIndex >= m_nLineCount) {
throw new ArgumentOutOfRangeException("nIndex");
}
return m_lines[nIndex];
}
}
private int m_nLineCount;
private int m_nTextLength;
private TextLine[] m_lines;
public TextManager() {
m_lines = new TextLine[2];
m_lines[0] = new TextLine();
m_nLineCount++;
}
public event TextManagerLineEventHandler LineAdded;
public event TextManagerLineEventHandler LineRemoved;
public event TextManagerLineEventHandler LineChanged;
public event TextManagerTextEventHandler TextChanged;
public event TextManagerTextEventHandler TextStartChange;
public event EventHandler LineCountChanged;
#region Event
protected virtual void OnTextStartChange(TextManagerTextEventArgs e) {
if (this.TextStartChange != null) {
this.TextStartChange(this, e);
}
}
protected virtual void OnLineAdded(TextManagerLineEventArgs e) {
if (this.LineAdded != null) {
this.LineAdded(this, e);
}
}
protected virtual void OnRemoveLine(TextManagerLineEventArgs e) {
if (this.LineRemoved != null) {
this.LineRemoved(this, e);
}
}
protected virtual void OnTextChanged(TextManagerTextEventArgs e) {
if (this.TextChanged != null) {
this.TextChanged(this, e);
}
}
protected virtual void OnLineChanged(TextManagerLineEventArgs e) {
if (this.LineChanged != null) {
this.LineChanged(this, e);
}
}
protected virtual void OnLineCountChanged(EventArgs e) {
if (this.LineCountChanged != null) {
this.LineCountChanged(this, e);
}
}
#endregion
public string GetText() {
return this.GetStringBuilder(0, m_nTextLength).ToString();
}
public string GetText(int nIndex, int nLen) {
return this.GetStringBuilder(nIndex, nLen).ToString();
}
public StringBuilder GetStringBuilder() {
return this.GetStringBuilder(0, m_nTextLength);
}
public StringBuilder GetStringBuilder(int nIndex, int nLen) {
StringBuilder sb = new StringBuilder();
if (nLen == 0) {
return sb;
}
int nIndexStart = this.GetLineIndexFromCharIndex(nIndex);
int nIndexEnd = this.GetLineIndexFromCharIndex(nIndex + nLen);
TextLine stLineStart = this[nIndexStart];
TextLine stLineEnd = this[nIndexEnd];
if (stLineStart == stLineEnd) {
sb.Append(stLineStart.RawString.Substring(nIndex - stLineStart.IndexOfFirstChar, nLen));
return sb;
}
int nLenAdded = 0;
sb.Append(stLineStart.RawString.Substring(nIndex - stLineStart.IndexOfFirstChar));
nLenAdded += sb.Length;
for (int i = nIndexStart + 1; i < nIndexEnd; i++) {
sb.Append(this[i].RawString);
nLenAdded += this[i].RawString.Length;
}
sb.Append(stLineEnd.RawString.Substring(0, nLen - nLenAdded));
return sb;
}
public TextHistoryRecord SetText(string strText) {
return this.SetText(0, m_nTextLength, strText);
}
public TextHistoryRecord SetText(int nIndex, string strText) {
return this.SetText(nIndex, 0, strText);
}
/// <summary>
/// Modify the source text
/// </summary>
/// <param name="nIndex">The index from source string</param>
/// <param name="nLen">The length of the text to be deleted</param>
/// <param name="strText">The text that will be add</param>
public TextHistoryRecord SetText(int nIndex, int nLen, string strText) {
return this.SetText(nIndex, nLen, strText, false);
}
public TextHistoryRecord[] RunHistory(TextHistoryRecord[] histories) {
if (histories == null || histories.Length == 0) {
return new TextHistoryRecord[0];
}
int nLineCount = m_nLineCount;
this.OnTextStartChange(new TextManagerTextEventArgs(new List<TextHistoryRecord>(histories)));
var ret = new TextHistoryRecord[histories.Length];
for (int i = 0; i < histories.Length; i++) {
var h = histories[i];
ret[i] = this.SetText(h.Index, h.OldText.Length, h.NewText, true);
}
if (m_nLineCount != nLineCount) {
this.OnLineCountChanged(EventArgs.Empty);
}
this.OnTextChanged(new TextManagerTextEventArgs(new List<TextHistoryRecord>(ret)));
return ret;
}
public int Clear() {
int nRet = m_nTextLength;
m_lines = new TextLine[2];
m_lines[0] = new TextLine();
m_nLineCount = 1;
m_nTextLength = 0;
return nRet;
}
public TextLine GetLineFromCharIndex(int nIndex) {
nIndex = this.GetLineIndexFromCharIndex(nIndex);
return m_lines[nIndex];
}
public int GetLineIndexFromCharIndex(int nIndex) {
if (m_nLineCount == 0) {
return -1;
}
if (nIndex <= 0) {
return 0;
}
if (nIndex >= m_lines[m_nLineCount - 1].IndexOfFirstChar + m_lines[m_nLineCount - 1].RawString.Length) {
return m_nLineCount - 1;
}
int nLeft = 0, nRight = m_nLineCount - 1, nMid = 0;
while (nLeft <= nRight) {
nMid = (nRight + nLeft) >> 1;
if (nIndex >= m_lines[nMid].IndexOfFirstChar + m_lines[nMid].RawString.Length) {
nLeft = nMid + 1;
} else if (nIndex < m_lines[nMid].IndexOfFirstChar) {
nRight = nMid - 1;
} else {
return nMid;
}
}
return -1;
}
public int GetLineIndexFromLine(TextLine line) {
int nLeft = 0, nRight = m_nLineCount - 1, nMid = 0;
while (nLeft <= nRight) {
nMid = (nLeft + nRight) >> 1;
if (line.IndexOfFirstChar < m_lines[nMid].IndexOfFirstChar) {
nRight = nMid - 1;
} else if (line.IndexOfFirstChar > m_lines[nMid].IndexOfFirstChar) {
nLeft = nMid + 1;
} else {
if (m_lines[nMid] == line) {
return nMid;
}
return -1;
}
}
return -1;
}
public TextHistoryRecord[] InsertAtStart(int nLineIndex, int nLineCount, string strText) {
if (nLineIndex < 0) {
nLineCount += nLineCount;
nLineIndex = 0;
}
if (nLineIndex >= m_nLineCount) {
return new TextHistoryRecord[0];
}
if (nLineIndex + nLineCount > m_nLineCount) {
nLineCount = m_nLineCount - nLineIndex;
}
TextHistoryRecord[] lst = new TextHistoryRecord[nLineCount];
this.OnTextStartChange(new TextManagerTextEventArgs(new List<TextHistoryRecord>(lst)));
int nAddCounter = 0;
for (int i = 0; i < nLineCount; i++) {
var line = m_lines[nLineIndex + i];
line.RawString = strText + line.RawString;
line.IndexOfFirstChar += nAddCounter;
var thr = new TextHistoryRecord() {
Index = line.IndexOfFirstChar,
OldText = string.Empty,
NewText = strText
};
lst[i] = thr;
this.OnLineChanged(new TextManagerLineEventArgs(nLineIndex + i, line, thr));
nAddCounter += strText.Length;
}
for (int i = nLineIndex + nLineCount; i < m_nLineCount; i++) {
m_lines[i].IndexOfFirstChar += nAddCounter;
}
m_nTextLength += nAddCounter;
this.OnTextChanged(new TextManagerTextEventArgs(new List<TextHistoryRecord>(lst)));
return lst;
}
public List<TextHistoryRecord> TrimStartTab(int nLineIndex, int nLineCount, int nTabSize) {
List<TextHistoryRecord> lst = new List<TextHistoryRecord>();
if (nLineIndex < 0) {
nLineCount += nLineCount;
nLineIndex = 0;
}
if (nLineIndex >= m_nLineCount) {
return lst;
}
if (nLineIndex + nLineCount > m_nLineCount) {
nLineCount = m_nLineCount - nLineIndex;
}
bool bStarted = false;
int nRemoveCounter = 0, nRemoveLen = 0;
for (int i = 0; i < nLineCount; i++) {
nRemoveLen = 0;
var thr = new TextHistoryRecord();
var line = m_lines[nLineIndex + i];
if (line.RawString[0] == '\t') {
nRemoveLen = 1;
} else {
while (nRemoveLen < nTabSize) {
switch (line.RawString[nRemoveLen]) {
case ' ':
nRemoveLen++;
continue;
case '\t':
nRemoveLen++;
continue;
default:
break;
}
break;
}
}
line.IndexOfFirstChar -= nRemoveCounter;
if (nRemoveLen == 0) continue;
if (!bStarted) {
this.OnTextStartChange(new TextManagerTextEventArgs(lst));
bStarted = true;
}
thr.OldText = line.RawString.Substring(0, nRemoveLen);
thr.Index = line.IndexOfFirstChar;
thr.NewText = "";
line.RawString = line.RawString.Substring(nRemoveLen);
nRemoveCounter += nRemoveLen;
this.OnLineChanged(new TextManagerLineEventArgs(nLineIndex + i, line, thr));
lst.Add(thr);
}
if (lst.Count == 0) return lst;
for (int i = nLineIndex + nLineCount; i < m_nLineCount; i++) {
m_lines[i].IndexOfFirstChar -= nRemoveCounter;
}
m_nTextLength -= nRemoveCounter;
this.OnTextChanged(new TextManagerTextEventArgs(lst));
return lst;
}
#region Private
private TextHistoryRecord SetText(int nIndex, int nLen, string strText, bool isHistory) {
if (strText == null) {
strText = "";
}
string strOld = string.Empty;
if (nLen != 0) {
strOld = this.GetText(nIndex, nLen);
}
if (strOld == strText) {
return TextHistoryRecord.Empty;
}
var historyRecord = new TextHistoryRecord() {
Index = nIndex,
OldText = strOld,
NewText = strText
};
if (!isHistory) {
var lstHistory = new List<TextHistoryRecord>() { historyRecord };
this.OnTextStartChange(new TextManagerTextEventArgs(lstHistory));
historyRecord = lstHistory[0];
}
List<TextLine> lst = this.GetTexLines(historyRecord.NewText);
int nIndexStartLine = this.GetLineIndexFromCharIndex(nIndex);
int nIndexEndLine = this.GetLineIndexFromCharIndex(nIndex + nLen);
var line_start = m_lines[nIndexStartLine];
var line_end = m_lines[nIndexEndLine];
string strLeft = line_start.RawString.Substring(0, nIndex - line_start.IndexOfFirstChar);
string strRight = line_end.RawString.Substring(nIndex + nLen - line_end.IndexOfFirstChar);
lst[0].RawString = strLeft + lst[0].RawString;
lst[0].IndexOfFirstChar = line_start.IndexOfFirstChar;
lst[lst.Count - 1].RawString += strRight;
int nIncrement = historyRecord.NewText.Length - nLen;
m_nTextLength += nIncrement;
line_start.RawString = lst[0].RawString;
this.OnLineChanged(new TextManagerLineEventArgs(strLeft.Length, line_start, historyRecord));
int nShouldRemoveLines = nIndexEndLine - nIndexStartLine;
int nShouldAddLines = lst.Count - 1 - nShouldRemoveLines;
for (int i = nIndexStartLine + 1; i <= nIndexEndLine; i++) {
this.OnRemoveLine(new TextManagerLineEventArgs(i, m_lines[i], historyRecord));
}
if (nShouldAddLines > 0) {
this.InsertEmptyLines(nIndexStartLine, nShouldAddLines, nIncrement);
} else {
this.RemoveLines(nIndexStartLine + 1, -nShouldAddLines, nIncrement, historyRecord);
}
for (int i = 1, j = nIndexStartLine + 1; i < lst.Count; i++, j++) {
var prev_line = m_lines[j - 1];
m_lines[j] = lst[i];
m_lines[j].IndexOfFirstChar = prev_line.IndexOfFirstChar + prev_line.RawString.Length;
this.OnLineAdded(new TextManagerLineEventArgs(j, m_lines[j], historyRecord));
}
if (nShouldAddLines == 0) {
for (int i = nIndexStartLine + 1; i < m_nLineCount; i++) {
TextLine prve_line = m_lines[i - 1];
m_lines[i].IndexOfFirstChar = prve_line.IndexOfFirstChar + prve_line.RawString.Length;
}
} else {
m_nLineCount += nShouldAddLines;
if (!isHistory) {
this.OnLineCountChanged(EventArgs.Empty);
}
}
if (!isHistory) {
this.OnTextChanged(new TextManagerTextEventArgs(new List<TextHistoryRecord>() { historyRecord }));
}
return historyRecord;
}
private List<TextLine> GetTexLines(string strText) {
int nIndexStart = 0, nLen = 0;
TextLine line = new TextLine();
List<TextLine> lst = new List<TextLine>();
lst.Add(line);
for (int i = 0; i < strText.Length; i++) {
char c = strText[i];
nLen++;
if (c == '\n' || c == '\r') {
if (c == '\r' && i + 1 < strText.Length && strText[i + 1] == '\n') {
nLen++;
i++;
}
line.RawString = strText.Substring(nIndexStart, nLen);
line = new TextLine();
lst.Add(line);
nIndexStart = i + 1;
nLen = 0;
}
}
if (nLen != 0) {
line.RawString = strText.Substring(nIndexStart, nLen);
}
return lst;
}
private void InsertEmptyLines(int nIndex, int nCount, int nOffsetIncrement) {
if (nCount == 0) return;
this.EnsureSpace(nCount);
for (int i = m_nLineCount + nCount - 1; i > nIndex + nCount; i--) {
m_lines[i] = m_lines[i - nCount];
if (m_lines[i] == null) {
m_lines[i] = new TextLine();
}
m_lines[i].IndexOfFirstChar += nOffsetIncrement;
}
}
private void RemoveLines(int nIndex, int nCount, int nOffsetIncrement, TextHistoryRecord history) {
if (nCount == 0) return;
int nCounter = nCount;
for (int i = nIndex; i < m_nLineCount - nCount; i++) {
if (nCounter > 0) {
nCounter--;
}
m_lines[i] = m_lines[i + nCount];
m_lines[i].IndexOfFirstChar += nOffsetIncrement;
}
}
private void EnsureSpace(int nCount) {
if (m_nLineCount + nCount <= m_lines.Length) {
return;
}
int nLen = m_nLineCount + nCount;
TextLine[] new_arr = new TextLine[Math.Max(m_nLineCount + nCount, m_lines.Length << 1)];
Array.Copy(m_lines, new_arr, m_lines.Length);
m_lines = new_arr;
}
#endregion
#region Interface
public IEnumerator<TextLine> GetEnumerator() {
for (int i = 0; i < m_nLineCount; i++) {
yield return m_lines[i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
#endregion
}
}

View File

@ -1,119 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
namespace ST.Library.UI.STTextBox
{
internal class Win32
{
//[DllImport("user32.dll")]
//public static extern IntPtr GetDC(IntPtr hWnd);
//[DllImport("user32.dll")]
//public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
//[DllImport("gdi32.dll")]
//public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
//[DllImport("gdi32.dll")]
//public static extern bool DeleteDC(IntPtr hDC);
//[DllImport("gdi32.dll")]
//public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);
//[DllImport("gdi32.dll")]
//public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
//[DllImport("gdi32.dll")]
//public static extern bool DeleteObject(IntPtr hObject);
//[DllImport("gdi32.dll")]
//public static extern int SetBkMode(IntPtr hDC, int iBkMode);
//[DllImport("gdi32.dll")]
//public static extern int SetTextCharacterExtra(IntPtr hDC, int nCharExtra);
//[DllImport("gdi32.dll")]
//public static extern uint SetTextColor(IntPtr hdc, int color);
//[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
//public static extern bool TextOut(IntPtr hdc, int nXStart, int nYStart, string lpString, int cbString);
//[DllImport("gdi32.dll", CharSet = CharSet.Auto)]
//public static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, ref Size lpSize);
[DllImport("user32.dll")]
public static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
public static extern bool ShowCaret(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool HideCaret(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool SetCaretPos(int x, int y);
[DllImport("user32.dll")]
public static extern bool DestroyCaret();
[DllImport("imm32.dll")]
public static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("Imm32.dll")]
public static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("Imm32.dll", CharSet = CharSet.Unicode)]
public static extern int ImmGetCompositionString(IntPtr hIMC, int dwIndex, byte[] lpBuf, int dwBufLen);
[DllImport("imm32.dll")]
public static extern bool ImmSetCandidateWindow(IntPtr hImc, ref CANDIDATEFORM fuck);
[DllImport("imm32.dll")]
public static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref COMPOSITIONFORM lpCompForm);
[DllImport("imm32.dll")]
public static extern bool ImmSetCompositionFont(IntPtr hIMC, ref LOGFONT logFont);
public const int SRCCOPY = 0x00CC0020;
public const int GCS_COMPSTR = 0x0008;
public const int GCS_RESULTSTR = 0x0800;
public const int WM_IME_REQUEST = 0x0288;
public const int WM_IME_COMPOSITION = 0x010F;
public const int WM_IME_ENDCOMPOSITION = 0x010E;
public const int WM_IME_STARTCOMPOSITION = 0x010D;
// bit field for IMC_SETCOMPOSITIONWINDOW, IMC_SETCANDIDATEWINDOW
public const int CFS_DEFAULT = 0x0000;
public const int CFS_RECT = 0x0001;
public const int CFS_POINT = 0x0002;
public const int CFS_FORCE_POSITION = 0x0020;
public const int CFS_CANDIDATEPOS = 0x0040;
public const int CFS_EXCLUDE = 0x0080;
public struct CANDIDATEFORM
{
public int dwIndex;
public int dwStyle;
public Point ptCurrentPos;
public Rectangle rcArea;
}
public struct COMPOSITIONFORM
{
public int dwStyle;
public Point ptCurrentPos;
public Rectangle rcArea;
}
public struct LOGFONT
{
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
public string lfFaceName;
}
private static byte[] m_byString = new byte[1024];
public static string ImmGetCompositionString(IntPtr hIMC, int dwIndex) {
if (hIMC == IntPtr.Zero) {
return null;
}
int nLen = Win32.ImmGetCompositionString(hIMC, dwIndex, m_byString, m_byString.Length);
return Encoding.Unicode.GetString(m_byString, 0, nLen);
}
}
}

View File

@ -1,12 +0,0 @@
using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Text;
namespace CPF.Drawing
{
public class StringFormat
{
public TextAlignment Alignment { get; internal set; }
}
}

View File

@ -185,7 +185,7 @@ namespace CPF.Controls
s = DrawingFactory.Default.MeasureString(text, font, size.Width);
if (TextTrimming == TextTrimming.CharacterEllipsis)
{
var fh = font.DefaultLineHeight;
var fh = font.LineHeight;
if (size.Height > fh && s.Height > size.Height && size.Height % fh > 0.001)
{
s.Height = (int)(size.Height / fh) * fh;
@ -197,7 +197,7 @@ namespace CPF.Controls
s = DrawingFactory.Default.MeasureString(text, font, size.Width);
if (TextTrimming == TextTrimming.CharacterEllipsis)
{
var fh = font.DefaultLineHeight;
var fh = font.LineHeight;
if (size.Height > fh && s.Height > size.Height && size.Height % fh > 0.001)
{
s.Height = (int)(size.Height / fh) * fh;

View File

@ -842,6 +842,42 @@ namespace CPF.Controls
TextBoxView.UpdateCaretPosition();
}
public void Undo()
{
if (!IsReadOnly && IsUndoEnabled)
{
if (undoRedoStates.Count > 1 && undoIndex > 0)
{
isRedo = true;
undoIndex--;
Document.Children.Clear();
document.Children.AddRange(undoRedoStates[undoIndex].Items);
caretIndex.Clear();
caretIndex.Add(undoRedoStates[undoIndex].CaretPosition);
selectionEnd.Clear();
//isRedo = false;
}
}
}
public void Redo()
{
if (!IsReadOnly && IsUndoEnabled)
{
if (undoIndex < undoRedoStates.Count - 1)
{
isRedo = true;
undoIndex++;
Document.Children.Clear();
document.Children.AddRange(undoRedoStates[undoIndex].Items);
caretIndex.Clear();
caretIndex.Add(undoRedoStates[undoIndex].CaretPosition);
selectionEnd.Clear();
//isRedo = false;
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
@ -993,36 +1029,10 @@ namespace CPF.Controls
}
break;
case PlatformHotkey.Undo:
if (!IsReadOnly && IsUndoEnabled)
{
if (undoRedoStates.Count > 1 && undoIndex > 0)
{
isRedo = true;
undoIndex--;
Document.Children.Clear();
document.Children.AddRange(undoRedoStates[undoIndex].Items);
caretIndex.Clear();
caretIndex.Add(undoRedoStates[undoIndex].CaretPosition);
selectionEnd.Clear();
//isRedo = false;
}
}
Undo();
break;
case PlatformHotkey.Redo:
if (!IsReadOnly && IsUndoEnabled)
{
if (undoIndex < undoRedoStates.Count - 1)
{
isRedo = true;
undoIndex++;
Document.Children.Clear();
document.Children.AddRange(undoRedoStates[undoIndex].Items);
caretIndex.Clear();
caretIndex.Add(undoRedoStates[undoIndex].CaretPosition);
selectionEnd.Clear();
//isRedo = false;
}
}
Redo();
break;
default:
break;

View File

@ -323,7 +323,7 @@ namespace CPF.Controls
line.Measure(availableSize);
if (document.Children.Count == 0)
{
return new Size(1, font.DefaultLineHeight);
return new Size(1, font.LineHeight);
}
return new Size(((IDocumentElement)document).Width, document.Height);
}
@ -350,7 +350,7 @@ namespace CPF.Controls
//return finalSize;
if (document.Children.Count == 0)
{
return new Size(1, font.DefaultLineHeight);
return new Size(1, font.LineHeight);
}
return new Size(((IDocumentElement)document).Width, document.Height);
}

View File

@ -66,7 +66,7 @@ namespace CPF.Controls
}
public View()
{
views.TryAdd(this,this);
views.TryAdd(this, this);
IsRoot = true;
Root = this;
viewImpl = CreateView();
@ -187,6 +187,14 @@ namespace CPF.Controls
list.Add(new CPFPropertyInfo { Name = item.Name, Value = e.ToString(), IsReadOnly = true, TypeName = item.PropertyType.FullName, GCHandle = ele.GetIntPtr().ToInt64() });
}
}
if (ele.attachedValues != null)
{
foreach (var item in ele.attachedValues)
{
list.Add(new CPFPropertyInfo { Name = item.Key, Value = item.Value == null ? "" : item.Value.ToString(), IsReadOnly = true, TypeName = item.Value != null ? item.Value.GetType().FullName : "", GCHandle = ele.GetIntPtr().ToInt64() });
}
}
SendData(new CommandMessage<List<CPFPropertyInfo>> { MessageType = MessageType.Properties, Data = list });
}
SetDrawRenderRectangle(ele);
@ -330,8 +338,12 @@ namespace CPF.Controls
{
info += "\n" + "普通属性";
}
SendData(new CommandMessage<string> { MessageType = MessageType.GetPropertyInfo, Data = info });
}
else if (p.PropertyName.Contains("."))
{
info += "\n附加属性";
}
SendData(new CommandMessage<string> { MessageType = MessageType.GetPropertyInfo, Data = info });
}
catch (Exception e)
{

View File

@ -1995,6 +1995,14 @@ namespace CPF
{
return objInfo.ContainsKey(propertyName);
}
/// <summary>
/// 获取所有注册了的属性元数据
/// </summary>
/// <returns></returns>
public virtual IEnumerable<PropertyMetadataAttribute> GetProperties()
{
return propertyInfos;
}
#region IDisposable Support
private bool disposedValue = false;

View File

@ -1587,6 +1587,42 @@ namespace CPF.Drawing
return c1;
}
public static Color FromArgb(int argb)
{
return FromArgb((byte)(argb >> 24),
(byte)((argb >> 16) & 0xff),
(byte)((argb >> 8) & 0xff),
(byte)(argb & 0xff));
}
/// <summary>
/// Construct color value with merged RGB int value.
/// </summary>
/// <param name="rgb">Merged RGB value to create color object.</param>
public static Color FromRgb(int rgb)
{
return FromRgb(
(byte)((rgb >> 16) & 0xff),
(byte)((rgb >> 8) & 0xff),
(byte)(rgb & 0xff));
}
public static Color FromColor(byte alpha, Color rgb)
{
return FromArgb(alpha, rgb.R, rgb.G, rgb.B);
}
private static Random rand;
/// <summary>
/// Randomly generate a color.
/// </summary>
/// <returns>New random solid color.</returns>
public static Color Randomly()
{
if (rand == null) rand = new Random();
return FromRgb((byte)rand.Next(255), (byte)rand.Next(255), (byte)rand.Next(255));
}
///<summary>
/// FromScRgb
///</summary>
@ -1856,6 +1892,24 @@ namespace CPF.Drawing
return false;
}
/// <summary>
/// Convert color value to 4 bytes integer value.
/// </summary>
/// <returns>Converted 4 bytes integer value.</returns>
public int ToArgb()
{
return (this.A << 24) | (this.R << 16) | (this.G << 8) | (this.B << 0);
}
/// <summary>
/// Check whether or not this color is transparent.
/// </summary>
public bool IsTransparent
{
get { return this.A == 0; }
}
/// <summary>
/// Parses a color string. #ffffff、r,g,b、r,g,b,a
/// </summary>

View File

@ -170,7 +170,19 @@ namespace CPF.Drawing
/// </summary>
/// <param name="font"></param>
/// <returns></returns>
public abstract float GetDefaultLineHeight(in Font font);
public abstract float GetLineHeight(in Font font);
/// <summary>
/// 获取从字样的基线到英语大写字母顶部的距离。
/// </summary>
/// <param name="font"></param>
/// <returns></returns>
public abstract float GetAscent(in Font font);
/// <summary>
/// 获取从字样的基线到行底部的距离。
/// </summary>
/// <param name="font"></param>
/// <returns></returns>
public abstract float GetDescent(in Font font);
public abstract void Dispose();
/// <summary>

View File

@ -22,6 +22,9 @@ namespace CPF.Drawing
this.FontFamily = fontfamily;
this.FontSize = size;
this.FontStyle = fontstyle;
ascent = 0;
descent = 0;
lineHeight = 0;
}
//public Font(IDisposable font, string fontfamily, float size, FontStyles fontstyle)
@ -76,13 +79,54 @@ namespace CPF.Drawing
}
//GC.SuppressFinalize(this);
}
float lineHeight;
/// <summary>
/// 字体默认行高
/// </summary>
public float DefaultLineHeight
public float LineHeight
{
get { return Platform.Application.GetDrawingFactory().GetDefaultLineHeight(this); }
get
{
if (lineHeight == 0)
{
lineHeight = Platform.Application.GetDrawingFactory().GetLineHeight(this);
}
return lineHeight;
}
}
float ascent;
/// <summary>
/// 获取从字样的基线到英语大写字母顶部的距离。
/// </summary>
public float Ascent
{
get
{
if (ascent == 0)
{
ascent = Platform.Application.GetDrawingFactory().GetAscent(this);
}
return ascent;
}
}
float descent;
/// <summary>
/// 获取从字样的基线到行底部的距离
/// </summary>
public float Descent
{
get
{
if (descent == 0)
{
descent = Platform.Application.GetDrawingFactory().GetDescent(this);
}
return descent;
}
}
//~Font()
//{
// Dispose();

View File

@ -26,5 +26,7 @@ namespace CPF.Drawing
bool Contains(float x, float y);
IPathImpl CreateStrokePath(float strokeWidth);
void Reset();
}
}

View File

@ -17,13 +17,28 @@ namespace CPF.Drawing
// blendColors = new GradientStop[] { new GradientStop(color1, 0), new GradientStop(color2, 1) };
//}
public LinearGradientBrush(GradientStop[] blendColors, Point startPoint, Point endPoint,Matrix matrix)
public LinearGradientBrush(GradientStop[] blendColors, Point startPoint, Point endPoint, Matrix matrix)
{
this.StartPoint = startPoint;
this.EndPoint = endPoint;
this.blendColors = blendColors;
Matrix = matrix;
}
//public LinearGradientBrush(GradientStop[] blendColors, float angle, Matrix matrix)
//{
// this.StartPoint = new Point();
// this.EndPoint = EndPointFromAngle(angle);
// this.blendColors = blendColors;
// Matrix = matrix;
//}
private Point EndPointFromAngle(float angle)
{
// Convert the angle from degrees to radians
angle = (float)(angle * (1.0 / 180.0) * System.Math.PI);
return (new Point((float)System.Math.Cos(angle), (float)System.Math.Sin(angle)));
}
GradientStop[] blendColors;

View File

@ -247,6 +247,11 @@ namespace CPF.Drawing
return base.ToString();
}
public void Reset()
{
PathIml.Reset();
}
#region IDisposable Support
protected virtual void Dispose(bool disposing)

View File

@ -69,18 +69,19 @@ namespace CPF.Drawing
public enum TextDecorationLocation : byte
{
None,
/// <summary>
/// 下划线的垂直位置。 这是默认值。
/// 下划线的垂直位置。
/// </summary>
Underline = 0,
Underline = 1,
/// <summary>
/// 上划线的垂直位置。
/// </summary>
OverLine = 1,
OverLine = 2,
/// <summary>
/// 删除线的垂直位置。
/// </summary>
Strikethrough = 2,
Strikethrough = 4,
}
}

View File

@ -28,7 +28,7 @@ namespace CPF
/// <param name="o"></param>
/// <param name="v"></param>
/// <returns></returns>
public static T Assign<T>(this T o,out T v)
public static T Assign<T>(this T o, out T v)
{
v = o;
return o;
@ -984,5 +984,15 @@ namespace CPF
//return base.GetPropertyMetadata(propertyName);
return new PropertyMetadataAttribute() { PropertyName = propertyName, PropertyType = row.Table.Columns[propertyName].DataType };
}
public override IEnumerable<PropertyMetadataAttribute> GetProperties()
{
List<PropertyMetadataAttribute> list = new List<PropertyMetadataAttribute>();
foreach (DataColumn item in row.Table.Columns)
{
list.Add(new PropertyMetadataAttribute { PropertyName = item.ColumnName, PropertyType = item.DataType, });
}
return list;
}
}
}