これは行頭にタブ文字を入れているのではありません。RichTextBox.SelectionIndentプロパティを設定することで行頭を右に寄せています。
では複数のRichTextBoxでインデントを同期させる方法について考えてみましょう。
やはり行頭にカーソルをもっていくことができればSelectionIndentに値を代入するだけでできるので、行頭を取得することから始めます。やることはこれとにています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
internal class IndentInfo { internal IndentInfo(int charIndex, int oldIndent, int newIndent, Indent indent) { CharIndex = charIndex; NewIndent = newIndent; OldIndent = oldIndent; Indent = indent; } internal Indent Indent { get; } = Indent.Indent; internal int CharIndex { get; } = 0; internal int NewIndent { get; } = 0; internal int OldIndent { get; } = 0; } |
1 2 3 4 5 6 |
enum Indent { Indent = 0, HangingIndent = 1, RightIndent = 2, } |
SelectionIndent
SelectionHangingIndent
SelectionRightIndent
3種類あるのですが、似たような処理なので引数を変えて同じメソッドでやってしまいます。
行をまるごと選択できるようにして、あとはカーソルを行頭に移動させて SelectionIndentの値を取得しています。そしてIndentInfoオブジェクトに行頭の位置、変更前のSelectionIndentの値、変更後のSelectionIndentの値を格納して、これをリストにしてUndobufオブジェクトに格納しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
public partial class SyncRichTextBox : UserControl { void SetIndent(int indent, Indent whatIndent, bool IsGrow) { List<int> vs = GetSelectedLineHeads(); int start = vs.Min(); int len = GetSelectedLineTail() - start; SelectionStart = start; SelectionLength = len; Undobuf buf = new Undobuf(); buf.oldSelectionLength = len; buf.newSelectionLength = len; buf.oldSelectionStart = start; buf.newSelectionStart = start; List<IndentInfo> indentInfos = new List<IndentInfo>(); foreach (int index in vs) { richTextBoxEx1.Select(index, 0); int oldIndent = richTextBoxEx1.SelectionIndent; int newIndent = indent; if (IsGrow) newIndent = oldIndent + indent; if (newIndent < 0) newIndent = 0; indentInfos.Add(new IndentInfo(index, oldIndent, newIndent, whatIndent)); } if (!indentInfos.Any(x => x.OldIndent != x.NewIndent)) return; buf.IndentInfos = indentInfos; if (whatIndent == Indent.Indent && !IsGrow) buf.action = "SetLeftIndent"; else if (whatIndent == Indent.Indent && IsGrow) buf.action = "PlusLeftIndent"; else if (whatIndent == Indent.HangingIndent && !IsGrow) buf.action = "SetHangingIndent"; else if (whatIndent == Indent.HangingIndent && IsGrow) buf.action = "PlusHangingIndent"; else if (whatIndent == Indent.RightIndent && !IsGrow) buf.action = "SetRightIndent"; else if (whatIndent == Indent.RightIndent && IsGrow) buf.action = "PlusRightIndent"; if (ChangeIndent(buf)) Data.InsertUndobuf(buf); } bool ChangeIndent(Undobuf buf) { foreach (var rich in Data.SyncRichTextBoxes) { rich.Data.GetRichTextBoxInfo(rich).SelectionStart = rich.SelectionStart; } OnTextChanging(buf); if (buf.IsCancel) return false; foreach (var rich in Data.SyncRichTextBoxes) { var info = rich.Data.GetRichTextBoxInfo(rich); int oldStart = info.SelectionStart; foreach (IndentInfo info1 in buf.IndentInfos) { if (rich.Data == Data) { rich.richTextBoxEx1.Select(info1.CharIndex, 0); if (info1.Indent == Indent.Indent) rich.richTextBoxEx1.SelectionIndent = info1.NewIndent; if (info1.Indent == Indent.HangingIndent) rich.richTextBoxEx1.SelectionHangingIndent = info1.NewIndent; if (info1.Indent == Indent.RightIndent) rich.richTextBoxEx1.SelectionRightIndent = info1.NewIndent; } } if (rich == this) { rich.SelectionStart = buf.NewSelectionStart; rich.SelectionLength = buf.NewSelectionLength; } else if (rich != this && rich.Data == Data) { rich.SelectionStart = oldStart; rich.SelectionLength = 0; } } return true; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class Undobuf { List<IndentInfo> _indentInfos = null; internal List<IndentInfo> IndentInfos { get { if (_indentInfos == null) return null; List<IndentInfo> ret = new List<IndentInfo>(); if (IsUndo) { foreach (var info in _indentInfos) { IndentInfo info1 = new IndentInfo(info.CharIndex, info.NewIndent, info.OldIndent, info.Indent); ret.Add(info1); } } else { foreach (var info in _indentInfos) { ret.Add(info); } } return ret; } set { _indentInfos = value; } } } |
SetIndentの第三引数で新しい値にセットするのか、現在の値にプラスするのか選べるようにしています。また0を下回った場合は0をセットしています。ここまできたら後は簡単。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public partial class SyncRichTextBox : UserControl { public int LeftIndent { set { SetIndent(value, Indent.Indent, false); } get { return richTextBoxEx1.SelectionIndent; } } public int LeftIndentPlus { set { SetIndent(value, Indent.Indent, true); } } public int HangingIndent { set { SetIndent(value, Indent.HangingIndent, false); } get { return richTextBoxEx1.SelectionHangingIndent; } } public int HangingIndentPlus { set { SetIndent(value, Indent.HangingIndent, true); } } public int RightIndent { set { SetIndent(value, Indent.RightIndent, false); } get { return richTextBoxEx1.SelectionRightIndent; } } public int RightIndentPlus { set { SetIndent(value, Indent.RightIndent, true); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class SyncRichTextBox : UserControl { protected override void OnKeyDown(KeyEventArgs e) { else if (e.KeyCode == Keys.Right && e.Control) { e.Handled = true; LeftIndentPlus = 50; return; } else if (e.KeyCode == Keys.Left && e.Control) { e.Handled = true; LeftIndentPlus = -50; return; } } } |
これでインデントを変更することができます。
Undo、Redoにも対応しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public partial class SyncRichTextBox : UserControl { public void Undo() { var buf = Data.GetUndobuf(); if (buf == null) return; buf.IsUndo = true; // 他の動作は省略 if (buf.IndentInfos != null) ChangeIndent(buf); buf.IsUndo = false; Data.MoveToRedobufs(); } public void Redo() { var buf = Data.GetRedobuf(); if (buf == null) return; // 他の動作は省略 if (buf.IndentInfos != null) ChangeIndent(buf); Data.MoveToUndobufs(); } } |