/* * テキストを変更して、変更情報をアンドゥ/リドゥのスタックにプッシュします。 */ void PushUndoRedoStack(int sel_start, int sel_end, string new_text, Stack <TDiff> dst_stack) { // 変更範囲にある改行文字の個数 int old_LF_cnt = GetLFCount(sel_start, sel_end); // 変更情報を作ります。 TDiff diff = new TDiff(sel_start, sel_end - sel_start, new_text.Length); // 変更情報をアンドゥのスタックにプッシュします。 dst_stack.Push(diff); // 削除する文字列をコピーします。 Chars.CopyTo(sel_start, diff.RemovedChars, 0, diff.RemovedChars.Length); // 文字列を削除します。 Chars.RemoveRange(sel_start, sel_end - sel_start); // 新しい文字列を挿入します。 Chars.InsertRange(sel_start, (from x in new_text select new TChar(x))); // アプリ内で持っているテキストの選択位置を更新します。 SelOrigin = sel_start + new_text.Length; SelCurrent = SelOrigin; // 新しく挿入した文字列に含まれる改行文字の個数 int new_LF_cnt = (from x in new_text where x == LF select x).Count();// GetLFCount(sel_start, sel_start + new_text.Length); // 文書の行数を更新します。 LineCount += new_LF_cnt - old_LF_cnt; }
/* * アンドゥとリドゥ */ void UndoRedo(bool is_undo) { Stack <TDiff> src_stack; Stack <TDiff> dst_stack; // アンドゥとリドゥは操作対象のスタックが違うだけです。 if (is_undo) { // アンドゥの場合 // アンドゥのスタックからポップして、リドゥのスタックにプッシュします。 src_stack = UndoStack; dst_stack = RedoStack; } else { // リドゥの場合 // リドゥのスタックからポップして、アンドゥのスタックにプッシュします。 src_stack = RedoStack; dst_stack = UndoStack; } if (src_stack.Count == 0) { // ポップするスタックが空の場合 return; } // 変更情報をポップします。 TDiff src_diff = src_stack.Pop(); // 削除された文字列 string removed_string = new string((from x in src_diff.RemovedChars select x.Chr).ToArray()); // テキストを変更して、変更情報をアンドゥ/リドゥのスタックにプッシュします。 PushUndoRedoStack(src_diff.DiffPos, src_diff.DiffPos + src_diff.InsertedCount, removed_string, dst_stack); // テキストの変更をIMEに伝えます。 MyNotifyTextChanged(src_diff.DiffPos, src_diff.DiffPos + src_diff.InsertedCount, src_diff.RemovedChars.Length); // 再描画します。 Win2DCanvas.Invalidate(); }