mirror of
https://github.com/chylex/Brotli-Builder.git
synced 2024-12-22 16:42:46 +01:00
230 lines
8.2 KiB
C#
230 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using BrotliBuilder.Utils;
|
|
using BrotliLib.Markers;
|
|
using FastColoredTextBoxNS;
|
|
|
|
namespace BrotliBuilder.Components{
|
|
public class MarkedTextBox : FastColoredTextBox{
|
|
private static readonly TextStyle[] MainStyles = Colors.List
|
|
.Select(color => Colors.Mix(SystemColors.Control, color, 0.725))
|
|
.Select(color => new TextStyle(new SolidBrush(Color.Black), new SolidBrush(color), FontStyle.Regular))
|
|
.ToArray();
|
|
|
|
private static readonly TextStyle HighlightStyle = new TextStyle(new SolidBrush(Color.White), new SolidBrush(Color.FromArgb(48, 48, 48)), FontStyle.Regular);
|
|
|
|
public class MarkerUpdateEventArgs : EventArgs{
|
|
public string? Title { get; }
|
|
public MarkerRoot MarkerRoot { get; }
|
|
public IList<MarkerNode> MarkerSequence { get; }
|
|
public HashSet<MarkerNode> HighlightedNodes { get; }
|
|
public MarkerNode? CaretNode { get; }
|
|
|
|
public MarkerUpdateEventArgs(string? title, MarkerRoot markerRoot, IList<MarkerNode> markerSequence, HashSet<MarkerNode> highlightedNodes, MarkerNode? caretNode){
|
|
this.Title = title;
|
|
this.MarkerRoot = markerRoot;
|
|
this.MarkerSequence = markerSequence;
|
|
this.HighlightedNodes = highlightedNodes;
|
|
this.CaretNode = caretNode;
|
|
}
|
|
}
|
|
|
|
public override string Text{
|
|
get{
|
|
return base.Text;
|
|
}
|
|
set{
|
|
updatingText = true;
|
|
base.Text = value;
|
|
updatingText = false;
|
|
}
|
|
}
|
|
|
|
public string? MarkerTitle { get; set; }
|
|
public MarkerRoot? MarkerRoot { get; private set; }
|
|
|
|
public event EventHandler<MarkerUpdateEventArgs>? MarkersUpdated;
|
|
|
|
private readonly StyleIndex[] mainStyleIndex;
|
|
private readonly StyleIndex highlightStyleIndex;
|
|
|
|
private MarkerNode[]? markerSequence = null;
|
|
private MarkerNode[]? prevMarkerSequence = null;
|
|
|
|
private MarkerNode? markerCaret = null;
|
|
private bool updatingText = false;
|
|
private bool updatingMarkers = false;
|
|
private bool mouseSelecting = false;
|
|
|
|
public MarkedTextBox(){
|
|
AllowSeveralTextStyleDrawing = true;
|
|
|
|
mainStyleIndex = MainStyles.Select(style => (StyleIndex)(1 << AddStyle(style))).ToArray();
|
|
highlightStyleIndex = (StyleIndex)(1 << AddStyle(HighlightStyle));
|
|
|
|
SelectionChanged += MarkedFastTextBox_SelectionChanged;
|
|
CustomAction += MarkedFastTextBox_CustomAction;
|
|
MouseDown += MarkedTextBox_MouseDown;
|
|
MouseUp += MarkedTextBox_MouseUp;
|
|
}
|
|
|
|
public void UpdateMarkers(MarkerRoot newMarkerRoot, MarkerNode[] newMarkerSequence){
|
|
markerSequence = newMarkerSequence;
|
|
MarkerRoot = newMarkerRoot;
|
|
RefreshMarkers();
|
|
prevMarkerSequence = newMarkerSequence;
|
|
}
|
|
|
|
public void RemoveMarkers(){
|
|
markerSequence = null;
|
|
markerCaret = null;
|
|
prevMarkerSequence = null;
|
|
ClearStyle(StyleIndex.All);
|
|
}
|
|
|
|
private void RefreshMarkers(){
|
|
if (markerSequence == null){
|
|
RemoveMarkers();
|
|
return;
|
|
}
|
|
|
|
bool recolorAll = markerSequence != prevMarkerSequence;
|
|
|
|
updatingMarkers = true;
|
|
Selection.BeginUpdate();
|
|
|
|
int caret = SelectionStart;
|
|
int maxDepth = -1;
|
|
List<MarkerNode> highlightedMarkers = new List<MarkerNode>();
|
|
|
|
ClearStyle(recolorAll ? StyleIndex.All : highlightStyleIndex);
|
|
|
|
foreach(MarkerNode node in markerSequence){
|
|
Marker marker = node.Marker;
|
|
int depth = node.Depth;
|
|
|
|
if (marker.HasIndex(caret)){
|
|
highlightedMarkers.Add(node);
|
|
maxDepth = Math.Max(depth, maxDepth);
|
|
}
|
|
else{
|
|
maxDepth = Math.Min(depth, maxDepth);
|
|
}
|
|
}
|
|
|
|
if (recolorAll){
|
|
int colorIndex = 0;
|
|
|
|
foreach(MarkerNode node in markerSequence){
|
|
Marker marker = node.Marker;
|
|
|
|
SelectionStart = marker.IndexStart;
|
|
SelectionLength = marker.Length;
|
|
|
|
Selection.ClearStyle(StyleIndex.All);
|
|
Selection.SetStyle(mainStyleIndex[colorIndex % mainStyleIndex.Length]);
|
|
|
|
++colorIndex;
|
|
}
|
|
}
|
|
|
|
MarkerNode? newMarkerCaret = markerCaret;
|
|
|
|
if (highlightedMarkers.Count > 0){
|
|
MarkerNode deepestNode = highlightedMarkers.Last();
|
|
Marker deepestMarker = deepestNode.Marker;
|
|
|
|
SelectionStart = deepestMarker.IndexStart;
|
|
SelectionLength = deepestMarker.Length;
|
|
|
|
Selection.SetStyle(highlightStyleIndex);
|
|
|
|
newMarkerCaret = deepestNode;
|
|
}
|
|
|
|
SelectionStart = caret;
|
|
SelectionLength = 0;
|
|
|
|
Selection.EndUpdate();
|
|
updatingMarkers = false;
|
|
|
|
markerCaret = newMarkerCaret;
|
|
MarkersUpdated?.Invoke(this, new MarkerUpdateEventArgs(MarkerTitle, MarkerRoot!, markerSequence, new HashSet<MarkerNode>(highlightedMarkers), markerCaret));
|
|
}
|
|
|
|
private void MarkedFastTextBox_SelectionChanged(object? sender, EventArgs e){
|
|
if (!updatingText && !updatingMarkers && !mouseSelecting && !ModifierKeys.HasFlag(Keys.Shift)){
|
|
RefreshMarkers();
|
|
}
|
|
}
|
|
|
|
private void MarkedFastTextBox_CustomAction(object? sender, CustomActionEventArgs e){
|
|
Keys key = e.Action switch{
|
|
FCTBAction.CustomAction1 => Keys.Left,
|
|
FCTBAction.CustomAction2 => Keys.Right,
|
|
_ => Keys.Escape
|
|
};
|
|
|
|
if ((key == Keys.Left || key == Keys.Right) && markerCaret != null){
|
|
int caret = SelectionStart;
|
|
|
|
int nodeIndex = Array.IndexOf(markerSequence!, markerCaret);
|
|
MarkerNode? targetNode = null;
|
|
|
|
if (key == Keys.Left){
|
|
while(--nodeIndex >= 0){
|
|
targetNode = markerSequence![nodeIndex];
|
|
|
|
int newCaret = targetNode.Marker.IndexStart;
|
|
|
|
if (caret != newCaret){
|
|
caret = newCaret;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (key == Keys.Right){
|
|
while(++nodeIndex < markerSequence!.Length){
|
|
targetNode = markerSequence[nodeIndex];
|
|
|
|
int newCaret = targetNode.Marker.IndexStart;
|
|
|
|
if (caret != newCaret){
|
|
caret = newCaret;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (targetNode != null){
|
|
Selection.BeginUpdate();
|
|
SelectionStart = caret;
|
|
Selection.End = Selection.Start;
|
|
Selection.EndUpdate();
|
|
|
|
markerCaret = targetNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MarkedTextBox_MouseDown(object? sender, MouseEventArgs e){
|
|
if (e.Button == MouseButtons.Left){
|
|
mouseSelecting = true;
|
|
}
|
|
}
|
|
|
|
private void MarkedTextBox_MouseUp(object? sender, MouseEventArgs e){
|
|
if (e.Button == MouseButtons.Left){
|
|
mouseSelecting = false;
|
|
|
|
if (Selection.Length == 0){
|
|
RefreshMarkers();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|