/* * Copyright (C) 2013 FooProject * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Threading; using System.Windows.Forms; using System.Drawing; using System.ComponentModel; using Microsoft.Win32; namespace FooEditEngine.Windows { /// /// タブの幅が変更されたときに呼びされるデリゲート /// /// 送り主が属するクラス /// イベントデータ public delegate void TabStopChangeEventHandler(object sender, EventArgs e); /// /// InsetModeが変更されたときに呼び出されるデリゲート /// /// 送り主が属するクラス /// イベントデータ public delegate void InsertModeChangeEventHandler(object sender, EventArgs e); /// /// FooEditEngineを表します /// public class FooTextBox : Control { EditView View; Controller Controller; D2DTextRender render; BorderStyle _BoderStyle; HScrollBar HScrollBar; VScrollBar VScrollBar; WinIME Ime; System.Windows.Forms.Timer Timer; const int Interval = 100; /// /// コンストラクター /// public FooTextBox() { this.VScrollBar = new VScrollBar(); this.VScrollBar.Scroll += new ScrollEventHandler(VScrollBar_Scroll); this.VScrollBar.Dock = DockStyle.Right; this.VScrollBar.Visible = true; this.Controls.Add(this.VScrollBar); this.HScrollBar = new HScrollBar(); this.HScrollBar.Scroll += new ScrollEventHandler(HScrollBar_Scroll); this.HScrollBar.Dock = DockStyle.Bottom; this.HScrollBar.Visible = true; this.Controls.Add(this.HScrollBar); this.SetStyle(ControlStyles.ResizeRedraw, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.Opaque, true); this.Document = new Document(); DocumentExtend.Progress += Document_Progress; this.render = new D2DTextRender(this); this.View = new EditView(this.Document,this.render,new FooEditEngine.Padding(5,5,5,5)); this.View.SrcChanged += View_SrcChanged; this.Controller = new Controller(this.Document, this.View); this.Controller.SelectionChanged += new EventHandler(Controller_CaretMoved); this.Ime = new WinIME(this); this.Ime.ImeCompstion += new ImeCompstionEventHandeler(Ime_ImeCompstion); this.Ime.StartCompstion += new StartCompstionEventHandeler(Ime_StartCompstion); this.Ime.EndCompstion += new EndCompstionEventHandeler(Ime_EndCompstion); this.Ime.ImeDocumentFeed += new ImeDocumentFeedEventHandler(Ime_ImeDocumentFeed); this.Ime.ImeReconvert += new ImeReconvertStringEventHandler(Ime_ImeReconvert); this.Ime.ImeQueryReconvert += new ImeQueryReconvertStringEventHandler(Ime_ImeQueryReconvert); this.Timer = new System.Windows.Forms.Timer(); this.Timer.Tick += new EventHandler(this.Timer_Tick); this.Timer.Interval = Interval; this.SetSystemParamaters(); this.TabStopChange += new TabStopChangeEventHandler((s, e) => { }); this.InsetModeChange += new InsertModeChangeEventHandler((s, e) => { }); this.SelectionChanged +=new EventHandler((s,e)=>{}); this.RightToLeftChanged += FooTextBox_RightToLeftChanged; SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(SystemEvents_UserPreferenceChanged); } /// /// キャレットが移動したときに通知されるイベント /// public event EventHandler SelectionChanged; /// /// タブの幅が変更された時に発生するイベント /// public event TabStopChangeEventHandler TabStopChange; /// /// InsertModeが変更されたときに呼び出されるイベント /// public event InsertModeChangeEventHandler InsetModeChange; /// /// テキスト描写に使用するアンチエイリアシングモードを表す /// [BrowsableAttribute(false)] public TextAntialiasMode TextAntialiasMode { get { return this.render.TextAntialiasMode; } set { this.render.TextAntialiasMode = value; } } /// /// マーカーパターンセットを表す /// [BrowsableAttribute(false)] public MarkerPatternSet MarkerPatternSet { get { return this.View.MarkerPatternSet; } } /// /// 保持しているドキュメント /// [BrowsableAttribute(false)] public Document Document { get; private set; } /// /// 保持しているレイアウト行 /// [BrowsableAttribute(false)] public LineToIndexTable LayoutLines { get { return this.View.LayoutLines; } } /// /// シンタックスハイライター /// [BrowsableAttribute(false)] public IHilighter Hilighter { get { return this.View.Hilighter; } set { this.View.Hilighter = value; this.View.LayoutLines.ClearLayoutCache(); } } /// /// フォールティングを作成するインターフェイスを表す /// [BrowsableAttribute(false)] public IFoldingStrategy FoldingStrategy { get { return this.View.LayoutLines.FoldingStrategy; } set { this.View.LayoutLines.FoldingStrategy = value; if (value == null) this.View.LayoutLines.FoldingCollection.Clear(); } } /// /// 境界線のスタイルを指定します /// public BorderStyle BorderStyle { get { return this._BoderStyle; } set { this._BoderStyle = value; this.UpdateStyles(); } } /// /// 行番号を表示するかどうか /// [DefaultValue(false)] public bool DrawLineNumber { get { return this.View.DrawLineNumber; } set { this.View.DrawLineNumber = value; this.JumpCaret(this.CaretPostion.row,this.CaretPostion.col); } } /// /// ルーラーを表示するかどうか /// [DefaultValue(false)] public bool DrawRuler { get { return !this.View.HideRuler; } set { this.View.HideRuler = !value; this.JumpCaret(this.CaretPostion.row, this.CaretPostion.col); } } /// /// 桁折りを行う方法を指定する /// /// /// 反映させるためにはレイアウト行の再構築を行う必要があります /// [DefaultValue(LineBreakMethod.None)] public LineBreakMethod LineBreakMethod { get { return this.View.LineBreak; } set { this.View.LineBreak = value; } } /// /// 桁折り時の文字数を指定する。 /// /// /// 反映させるためにはレイアウト行の再構築を行う必要があります /// [DefaultValue(80)] public int LineBreakCharCount { get { return this.View.LineBreakCharCount; } set { this.View.LineBreakCharCount = value; } } /// /// URLをマークするかどうか /// [DefaultValue(false)] public bool UrlMark { get { return this.View.UrlMark; } set { this.View.UrlMark = value; } } /// /// タブストップの幅 /// [DefaultValue(4)] public int TabStops { get { return this.View.TabStops; } set { this.View.TabStops = value; this.View.AdjustCaretAndSrc(); this.TabStopChange(this, null); } } /// /// 全角スペースを表示するなら真。そうでないなら偽 /// [DefaultValue(false)] public bool ShowFullSpace { get { return this.render.ShowFullSpace; } set { this.render.ShowFullSpace = value; } } /// /// 半角スペースを表示するなら真。そうでないなら偽 /// [DefaultValue(false)] public bool ShowHalfSpace { get { return this.render.ShowHalfSpace; } set { this.render.ShowHalfSpace = value; } } /// /// タブを表示するなら真。そうでないなら偽 /// [DefaultValue(false)] public bool ShowTab { get { return this.render.ShowTab; } set { this.render.ShowTab = value; } } /// /// 改行マークを表示するなら真。そうでないなら偽 /// [DefaultValue(false)] public bool ShowLineBreak { get { return this.render.ShowLineBreak; } set { this.render.ShowLineBreak = value; } } /// /// 選択中の文字列 /// /// /// 未選択状態で文字列を代入した場合、キャレット位置に挿入され、そうでないときは置き換えられます。 /// [BrowsableAttribute(false)] public string SelectedText { get { return this.Controller.SelectedText; } set { this.Controller.SelectedText = value; } } /// /// キャレット位置を表す /// [BrowsableAttribute(false)] public TextPoint CaretPostion { get { return this.View.CaretPostion; } } /// /// 選択範囲を表す /// /// /// Lengthが0の場合はキャレット位置を表します /// 矩形選択モードの場合、選択範囲の文字数ではなく、開始位置から終了位置までの長さとなります /// [BrowsableAttribute(false)] public TextRange Selection { get { return new TextRange(this.Controller.SelectionStart,this.Controller.SelectionLength); } set { this.Controller.Select(value.Index, value.Length); } } /// /// 挿入モードかどうか /// [DefaultValue(true)] public bool InsertMode { get { return this.View.InsertMode; } set { this.View.InsertMode = value; this.InsetModeChange(this, null); } } /// /// 矩形選択を行うかどうか /// [DefaultValue(false)] public bool RectSelection { get { return this.Controller.RectSelection; } set { this.Controller.RectSelection = value; } } /// /// 前景色 /// public System.Drawing.Color Foreground { get { return this.render.Foreground; } set { this.render.Foreground = value; } } /// /// 背景色 /// public System.Drawing.Color Background { get { return this.render.Background; } set { this.render.Background = value; } } /// /// 挿入モード時のキャレット色 /// public System.Drawing.Color InsertCaret { get { return this.render.InsertCaret; } set { this.render.InsertCaret = value; } } /// /// 上書きモード時のキャレット色 /// public System.Drawing.Color OverwriteCaret { get { return this.render.OverwriteCaret; } set { this.render.OverwriteCaret = value; } } /// /// ラインマーカーの色 /// public System.Drawing.Color LineMarker { get { return this.render.LineMarker; } set { this.render.LineMarker = value; } } /// /// コントロールの色 /// public System.Drawing.Color ControlChar { get { return this.render.ControlChar; } set { this.render.ControlChar = value; } } /// /// URLの色 /// public System.Drawing.Color Url { get { return this.render.Url; } set { this.render.Url = value; } } /// /// 選択領域の色 /// public System.Drawing.Color Hilight { get { return this.render.Hilight; } set { this.render.Hilight = value; } } /// /// コメントの色 /// public System.Drawing.Color Comment { get { return this.render.Comment; } set { this.render.Comment = value; } } /// /// 文字リテラルの色 /// public System.Drawing.Color Literal { get { return this.render.Literal; } set { this.render.Literal = value; } } /// /// キーワード1の色 /// public System.Drawing.Color Keyword1 { get { return this.render.Keyword1; } set { this.render.Keyword1 = value; } } /// /// キーワード2の色 /// public System.Drawing.Color Keyword2 { get { return this.render.Keyword2; } set { this.render.Keyword2 = value; } } /// /// キャレットに下線を描くかどうか /// [DefaultValue(false)] public bool DrawCaretLine { get { return !this.View.HideLineMarker; } set { this.View.HideLineMarker = !value; } } /// /// ドキュメントを選択する /// /// 開始インデックス /// 長さ public void Select(int start, int length) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); this.Controller.Select(start, length); this.HScrollBar.Value = (int)this.View.Src.X; this.VScrollBar.Value = this.View.Src.Row; } /// /// ドキュメント全体を選択する /// public void SelectAll() { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); this.Controller.Select(0, this.Document.Length - 1); } /// /// 選択を解除する /// public void DeSelectAll() { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); this.Controller.DeSelectAll(); } /// /// クリップボードにコピーする /// public void Copy() { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); string text = this.SelectedText; if(text != null && text != string.Empty) Clipboard.SetText(text); } /// /// クリップボードにコピーし、指定した範囲にある文字列をすべて削除します /// public void Cut() { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); string text = this.SelectedText; if (text != null && text != string.Empty) { Clipboard.SetText(text); this.Controller.SelectedText = ""; } } /// /// クリップボードの内容をペーストします /// public void Paste() { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); if (Clipboard.ContainsText() == false) return; this.Controller.SelectedText = Clipboard.GetText(); } /// /// キャレットを指定した行に移動させます /// /// インデックス /// このメソッドを呼び出すと選択状態は解除されます public void JumpCaret(int index) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); this.Controller.JumpCaret(index); } /// /// キャレットを指定した行と桁に移動させます /// /// 行番号 /// 桁 /// このメソッドを呼び出すと選択状態は解除されます public void JumpCaret(int row, int col) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); this.Controller.JumpCaret(row, col); } /// /// 再描写します /// public new void Refresh() { if (this.Document.State == AsyncState.Loading) return; if (this.Document.FireUpdateEvent == false) throw new InvalidOperationException(""); if(this.View.CaretBlink) this.View.CaretBlink = true; this.Invalidate(); this.Update(); } /// /// 行の高さを取得する /// /// 行 /// 高さ public double GetLineHeight(int row) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); if (this.Document.FireUpdateEvent == false) throw new InvalidOperationException(""); return this.View.LayoutLines.GetLayout(row).Height; } /// /// 対応する座標を返す /// /// テキストポイント /// 座標 /// テキストポイントがクライアント領域の原点より外にある場合、返される値は原点に丸められます public System.Drawing.Point GetPostionFromTextPoint(TextPoint tp) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); if (this.Document.FireUpdateEvent == false) throw new InvalidOperationException(""); return this.View.GetPostionFromTextPoint(tp); } /// /// 対応するテキストポイントを返す /// /// クライアント領域の原点を左上とする座標 /// テキストポイント public TextPoint GetTextPointFromPostion(System.Drawing.Point p) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); if (this.Document.FireUpdateEvent == false) throw new InvalidOperationException(""); return this.View.GetTextPointFromPostion(p); } /// /// インデックスに対応する座標を得ます /// /// インデックス /// 座標を返す public System.Drawing.Point GetPostionFromIndex(int index) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); if (this.Document.FireUpdateEvent == false) throw new InvalidOperationException(""); TextPoint tp = this.View.GetLayoutLineFromIndex(index); return this.View.GetPostionFromTextPoint(tp); } /// /// 座標からインデックスに変換します /// /// 座標 /// インデックスを返す public int GetIndexFromPostion(System.Drawing.Point p) { if (this.Document.State == AsyncState.Loading) throw new InvalidOperationException(); if (this.Document.FireUpdateEvent == false) throw new InvalidOperationException(""); TextPoint tp = this.View.GetTextPointFromPostion(p); return this.View.GetIndexFromLayoutLine(tp); } /// /// レイアウト行をすべて破棄し、再度レイアウトを行う /// public void PerfomLayouts() { this.View.PerfomLayouts(); initScrollBars(); } /// /// マウスカーソルを指定します /// public override Cursor Cursor { get { return base.Cursor; } set { base.Cursor = value; this.VScrollBar.Cursor = DefaultCursor; this.HScrollBar.Cursor = DefaultCursor; } } private const int WS_BORDER = 0x00800000; private const int WS_EX_CLIENTEDGE = 0x00000200; /// /// コントロールの外観を指定します /// protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; switch (this.BorderStyle) { case BorderStyle.Fixed3D: cp.ExStyle |= WS_EX_CLIENTEDGE; break; case BorderStyle.FixedSingle: cp.Style |= WS_BORDER; break; } return cp; } } /// /// コマンド キーを処理します /// /// メッセージ /// キーデータ /// 文字がコントロールによって処理された場合は true。それ以外の場合は false。 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (this.Document.State == AsyncState.Loading) return false; const int WM_KEYDOWN = 0x100; if (msg.Msg != WM_KEYDOWN) return base.ProcessCmdKey(ref msg, keyData); switch (keyData) { case Keys.Control | Keys.C: this.Copy(); break; case Keys.Control | Keys.V: this.Paste(); this.Refresh(); break; case Keys.Control | Keys.X: this.Cut(); this.Refresh(); break; case Keys.Control | Keys.Z: this.Document.UndoManager.undo(); this.Refresh(); break; case Keys.Control | Keys.Y: this.Document.UndoManager.redo(); this.Refresh(); break; case Keys.Control | Keys.B: if (this.Controller.RectSelection) this.Controller.RectSelection = false; else this.Controller.RectSelection = true; break; default: return base.ProcessCmdKey(ref msg,keyData); } return true; } /// /// インスタンスを破棄します /// /// マネージ リソースとアンマネージ リソースの両方を解放する場合は true。アンマネージ リソースだけを解放する場合は false。 protected override void Dispose(bool disposing) { SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.SystemEvents_UserPreferenceChanged); DocumentExtend.Progress -= this.Document_Progress; this.render.Dispose(); this.Timer.Dispose(); base.Dispose(disposing); } /// /// 入力可能な文字かチェックします /// /// 入力しようとした文字 /// 可能なら真。そうでなければ偽 protected override bool IsInputChar(char charCode) { if ((0x20 <= charCode && charCode <= 0x7e) || charCode == '\r' || charCode == '\n' || charCode == ' ' || charCode == '\t' || charCode == ' ' || 0x7f < charCode) { return true; } return false; } /// /// PaddingChangedイベントを発生させます /// /// インベントデータ protected override void OnPaddingChanged(EventArgs e) { base.OnPaddingChanged(e); this.View.Padding = new Padding(this.Padding.Left, this.Padding.Top, this.Padding.Right, this.Padding.Bottom); } /// /// GotFocusイベントを発生させます /// /// インベントデータ protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); this.View.IsFocused = true; this.Refresh(); } /// /// LostFocusイベントを発生させます /// /// インベントデータ protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); this.View.IsFocused = false; this.Refresh(); } /// /// FontChangedイベントを発生させます /// /// インベントデータ protected override void OnFontChanged(EventArgs e) { if (this.DesignMode) return; base.OnFontChanged(e); initScrollBars(); } /// /// MouseDownイベントを発生させます /// /// インベントデータ protected override void OnMouseDown(MouseEventArgs e) { if (this.Document.State == AsyncState.Loading) return; TextPoint tp = this.View.GetTextPointFromPostion(e.Location); if (tp == TextPoint.Null) return; int index = this.View.LayoutLines.GetIndexFromTextPoint(tp); FooMouseEventArgs mouseEvent = new FooMouseEventArgs(index, e.Button, e.Clicks, e.X, e.Y, e.Delta); base.OnMouseDown(mouseEvent); if (mouseEvent.Handled) return; if (e.Button == MouseButtons.Left) { FoldingItem foldingData = this.View.HitFoldingData(e.Location.X, tp.row); if (foldingData != null) { if (foldingData.Expand) this.View.LayoutLines.FoldingCollection.Collapse(foldingData); else this.View.LayoutLines.FoldingCollection.Expand(foldingData); this.Controller.JumpCaret(foldingData.Start, false); } else { this.Controller.JumpCaret(tp.row, tp.col, false); } this.View.IsFocused = true; this.Focus(); this.Refresh(); } } /// /// MouseClickイベントを発生させます /// /// インベントデータ protected override void OnMouseClick(MouseEventArgs e) { if (this.Document.State == AsyncState.Loading) return; int index = this.GetIndexFromPostion(e.Location); FooMouseEventArgs mouseEvent = new FooMouseEventArgs(index, e.Button, e.Clicks, e.X, e.Y, e.Delta); base.OnMouseClick(mouseEvent); } /// /// MouseDoubleClickイベントを発生させます /// /// インベントデータ protected override void OnMouseDoubleClick(MouseEventArgs e) { if (this.Document.State == AsyncState.Loading) return; TextPoint tp = this.View.GetTextPointFromPostion(e.Location); if (tp == TextPoint.Null) return; int index = this.View.LayoutLines.GetIndexFromTextPoint(tp); FooMouseEventArgs mouseEvent = new FooMouseEventArgs(index, e.Button, e.Clicks, e.X, e.Y, e.Delta); base.OnMouseDoubleClick(mouseEvent); if (mouseEvent.Handled) return; this.Controller.SelectWord(index); this.Refresh(); } /// /// MouseMoveイベントを発生させます /// /// インベントデータ protected override void OnMouseMove(MouseEventArgs e) { if (this.Document.State == AsyncState.Loading) { this.Cursor = Cursors.WaitCursor; return; } if (this.Focused == false) return; base.OnMouseMove(e); if (this.View.HitTextArea(e.Location.X, e.Location.Y)) { TextPoint tp = this.View.GetTextPointFromPostion(e.Location); if (this.Controller.IsMarker(tp, HilightType.Url)) this.Cursor = Cursors.Hand; else this.Cursor = Cursors.IBeam; if (e.Button == MouseButtons.Left) { this.Controller.MoveCaretAndSelect(tp); this.Refresh(); } } else { this.Cursor = Cursors.Arrow; } } /// /// MouseWheelイベントを発生させます /// /// インベントデータ protected override void OnMouseWheel(MouseEventArgs e) { if (this.Document.State == AsyncState.Loading) return; base.OnMouseWheel(e); ScrollDirection dir = e.Delta > 0 ? ScrollDirection.Up : ScrollDirection.Down; this.Controller.Scroll(dir, SystemInformation.MouseWheelScrollLines, false, false); this.Refresh(); } /// /// Paintイベントを発生させます /// /// インベントデータ protected override void OnPaint(PaintEventArgs e) { if (DesignMode || this.Document.State == AsyncState.Loading) { SolidBrush brush = new SolidBrush(this.BackColor); e.Graphics.FillRectangle(brush, this.ClientRectangle); brush.Dispose(); }else if (this.Document.FireUpdateEvent){ this.render.BeginDraw(); this.View.Draw(e.ClipRectangle); this.render.EndDraw(); } base.OnPaint(e); } /// /// PaintBackgroundイベントを発生させます /// /// インベントデータ protected override void OnPaintBackground(PaintEventArgs e) { } /// /// PreviewKeyDownイベントを発生させます /// /// インベントデータ protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) { base.OnPreviewKeyDown(e); switch (e.KeyCode) { case Keys.Up: case Keys.Down: case Keys.Left: case Keys.Right: case Keys.Tab: e.IsInputKey = true; break; } } /// /// KeyDownイベントを発生させます /// /// インベントデータ protected override void OnKeyDown(KeyEventArgs e) { if (this.Document.State == AsyncState.Loading) return; base.OnKeyDown(e); if (e.Handled) return; switch (e.KeyCode) { case Keys.Up: this.Controller.MoveCaretVertical(-1, e.Shift); this.Refresh(); break; case Keys.Down: this.Controller.MoveCaretVertical(+1, e.Shift); this.Refresh(); break; case Keys.Left: this.Controller.MoveCaretHorizontical(-1, e.Shift, e.Control); this.Refresh(); break; case Keys.Right: this.Controller.MoveCaretHorizontical(1, e.Shift, e.Control); this.Refresh(); break; case Keys.PageUp: this.Controller.Scroll(ScrollDirection.Up, this.VScrollBar.LargeChange,e.Shift,true); this.Refresh(); break; case Keys.PageDown: this.Controller.Scroll(ScrollDirection.Down, this.VScrollBar.LargeChange,e.Shift,true); this.Refresh(); break; case Keys.Insert: if (this.InsertMode) this.InsertMode = false; else this.InsertMode = true; break; case Keys.Delete: this.Controller.DoDeleteAction(); this.Refresh(); break; case Keys.Back: this.Controller.DoBackSpaceAction(); this.Refresh(); break; case Keys.Home: if (e.Control) this.Controller.JumpToHead(e.Shift); else this.Controller.JumpToLineHead(this.View.CaretPostion.row, e.Shift); this.Refresh(); break; case Keys.End: if (e.Control) this.Controller.JumpToEnd(e.Shift); else this.Controller.JumpToLineEnd(this.View.CaretPostion.row, e.Shift); this.Refresh(); break; case Keys.Tab: if (this.Controller.SelectionLength == 0) this.Controller.DoInputChar('\t'); else if (e.Shift) this.Controller.DownIndent(); else this.Controller.UpIndent(); this.Refresh(); break; } } /// /// KeyPressイベントを発生させます /// /// インベントデータ protected override void OnKeyPress(KeyPressEventArgs e) { if (this.Document.State == AsyncState.Loading) return; base.OnKeyPress(e); if (e.Handled) return; switch (e.KeyChar) { case '\r': this.Controller.DoEnterAction(); this.Refresh(); break; case '\t': break; //OnKeyDownで処理しているので不要 default: if (IsInputChar(e.KeyChar) == false) break; this.Controller.DoInputChar(e.KeyChar); this.Refresh(); break; } } /// /// ClientSizeChangedイベントを発生させます /// /// インベントデータ protected override void OnClientSizeChanged(EventArgs e) { if (this.DesignMode) return; base.OnClientSizeChanged(e); this.View.PageBound = new Rectangle(0, 0, Math.Max(this.ClientRectangle.Width - this.VScrollBar.Width,0), Math.Max(this.ClientRectangle.Height - this.HScrollBar.Height, 0)); initScrollBars(); this.Refresh(); } void View_SrcChanged(object sender, EventArgs e) { if (this.View.Src.Row > this.VScrollBar.Maximum) this.VScrollBar.Maximum = this.View.Src.Row + this.View.LineCountOnScreen + 1; int srcX = (int)Math.Abs(this.View.Src.X); if (srcX > this.HScrollBar.Maximum) this.HScrollBar.Maximum = srcX + (int)this.View.PageBound.Width + 1; this.HScrollBar.Value = srcX; this.VScrollBar.Value = this.View.Src.Row; } void FooTextBox_RightToLeftChanged(object sender, EventArgs e) { this.render.RightToLeft = this.RightToLeft == System.Windows.Forms.RightToLeft.Yes; } void VScrollBar_Scroll(object sender, ScrollEventArgs e) { if (this.Document.State == AsyncState.Loading) return; this.View.TryScroll(this.View.Src.X, e.NewValue); this.Refresh(); } void HScrollBar_Scroll(object sender, ScrollEventArgs e) { if (this.Document.State == AsyncState.Loading) return; int toX; if (this.RightToLeft == System.Windows.Forms.RightToLeft.Yes) toX = -e.NewValue; else toX = e.NewValue; this.View.TryScroll(toX, this.View.Src.Row); this.Refresh(); } void Ime_StartCompstion(object sender, StartCompstionEventArgs e) { if (this.Document.State == AsyncState.Loading) return; this.Ime.Font = this.Font; this.Ime.Location = this.GetPostionFromIndex(this.Controller.SelectionStart); this.View.HideCaret = true; } void Ime_EndCompstion(object sender, EndCompstionEventArgs e) { this.View.HideCaret = false; } void Ime_ImeCompstion(object sender, ImeCompstionEventArgs e) { if (this.Document.State == AsyncState.Loading) return; this.Controller.DoInputString(e.InputText); this.Refresh(); } void Ime_ImeDocumentFeed(object sender, ImeDocumentFeedEventArgs e) { if (this.Document.State == AsyncState.Loading) return; TextPoint tp = this.CaretPostion; e.Pragraph = this.LayoutLines[tp.row]; e.pos = tp.col; } void Ime_ImeReconvert(object sender, ImeReconvertStringEventArgs e) { if (this.Document.State == AsyncState.Loading) return; if (this.RectSelection) return; if (this.Controller.SelectionLength == 0) { TextPoint tp = this.LayoutLines.GetTextPointFromIndex(this.Controller.SelectionStart); e.TargetString = this.LayoutLines[tp.row]; e.AutoAdjust = true; } else { e.TargetString = this.SelectedText; if (e.TargetString.Length > 40) e.TargetString.Remove(40); } e.CaretPostion = this.View.CaretLocation; } void Ime_ImeQueryReconvert(object sender, ImeQueryRecovertStringEventArgs e) { if (this.Document.State == AsyncState.Loading) return; TextPoint tp = this.LayoutLines.GetTextPointFromIndex(this.Controller.SelectionStart); tp.col = e.offset; int index = this.View.GetIndexFromLayoutLine(tp); this.Select(index, index + e.length); } void Controller_CaretMoved(object sender, EventArgs e) { this.SelectionChanged(this, null); } void Document_Progress(object sender, ProgressEventArgs e) { if (this.Document.State == AsyncState.Saving) return; if (e.state == ProgressState.Complete) { this.initScrollBars(); this.OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, MousePosition.X, MousePosition.Y, 0)); this.View.CalculateLineCountOnScreen(); } } void initScrollBars() { this.VScrollBar.SmallChange = 1; this.VScrollBar.LargeChange = this.View.LineCountOnScreen; this.VScrollBar.Maximum = this.View.LayoutLines.Count + this.View.LineCountOnScreen + 1; this.HScrollBar.SmallChange = 10; this.HScrollBar.LargeChange = (int)this.View.PageBound.Width; this.HScrollBar.Maximum = this.HScrollBar.LargeChange + 1; } void Timer_Tick(object sender,EventArgs e) { if (this.Document.State == AsyncState.Loading) return; if (this.View.CaretPostion.row >= this.View.LayoutLines.Count || DesignMode) return; ITextLayout layout = this.View.LayoutLines.GetLayout(this.View.CaretPostion.row); Size redrawSize = new Size(); redrawSize.Width = layout.GetWidthFromIndex(this.View.CaretPostion.col); if (redrawSize.Width == 0.0) redrawSize.Width = this.View.CaretWidthOnInsertMode; redrawSize.Height = layout.Height; this.Invalidate(new System.Drawing.Rectangle(this.View.CaretLocation, redrawSize)); } void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { this.SetSystemParamaters(); this.Refresh(); } void SetSystemParamaters() { int CaretBlinkTime = SystemInformation.CaretBlinkTime; if (CaretBlinkTime == -1) { this.View.CaretBlink = false; this.BeginInvoke(new Action(() => { this.Timer.Stop(); })); } else { this.View.CaretBlink = true; this.View.CaretBlinkTime = CaretBlinkTime * 2; this.BeginInvoke(new Action(() => { this.Timer.Start(); })); } this.View.CaretWidthOnInsertMode = SystemInformation.CaretWidth; } } /// /// FooEditEngineで使用するマウスイベント /// public class FooMouseEventArgs : MouseEventArgs { /// /// イベントが発生したインデックス /// public int index; /// /// 既定の処理を省略するなら真。そうでなければ偽 /// public bool Handled; /// /// コンストラクター /// /// インデックス /// 押されているボタン /// ボタンが押された回数 /// マウスカーソルがあるX座標 /// マウスカーソルがあるY座標 /// ホイールの回転方向 public FooMouseEventArgs(int index, MouseButtons button, int clicks, int x, int y, int delta) : base(button, clicks, x, y, delta) { this.index = index; } } }