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