OSDN Git Service

bc0888f1a244078fa2d68b180ed1a846769367c3
[fooeditengine/FooEditEngine.git] / Windows / FooEditEngine / FooTextBox.cs
1 /*
2  * Copyright (C) 2013 FooProject
3  * * 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
4  * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
5
6  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
10  */
11 using System;
12 using System.Text;
13 using System.Threading;
14 using System.Threading.Tasks;
15 using System.Windows.Forms;
16 using System.Drawing;
17 using System.ComponentModel;
18 using Microsoft.Win32;
19
20 namespace FooEditEngine.Windows
21 {
22     /// <summary>
23     /// タブの幅が変更されたときに呼びされるデリゲート
24     /// </summary>
25     /// <param name="sender">送り主が属するクラス</param>
26     /// <param name="e">イベントデータ</param>
27     public delegate void TabStopChangeEventHandler(object sender, EventArgs e);
28
29     /// <summary>
30     /// InsetModeが変更されたときに呼び出されるデリゲート
31     /// </summary>
32     /// <param name="sender">送り主が属するクラス</param>
33     /// <param name="e">イベントデータ</param>
34     public delegate void InsertModeChangeEventHandler(object sender, EventArgs e);
35
36     /// <summary>
37     /// FooEditEngineを表します
38     /// </summary>
39     public class FooTextBox : Control
40     {
41         EditView View;
42         Controller Controller;
43         D2DTextRender render;
44         BorderStyle _BoderStyle;
45         HScrollBar HScrollBar;
46         VScrollBar VScrollBar;
47         WinIME Ime;
48         System.Windows.Forms.Timer Timer;
49
50         const int Interval = 100;
51
52         /// <summary>
53         /// コンストラクター
54         /// </summary>
55         public FooTextBox()
56         {
57             this.VScrollBar = new VScrollBar();
58             this.VScrollBar.Scroll += new ScrollEventHandler(VScrollBar_Scroll);
59             this.VScrollBar.Dock = DockStyle.Right;
60             this.VScrollBar.Visible = true;
61             this.Controls.Add(this.VScrollBar);
62
63             this.HScrollBar = new HScrollBar();
64             this.HScrollBar.Scroll += new ScrollEventHandler(HScrollBar_Scroll);
65             this.HScrollBar.Dock = DockStyle.Bottom;
66             this.HScrollBar.Visible = true;
67             this.Controls.Add(this.HScrollBar);
68
69             this.SetStyle(ControlStyles.ResizeRedraw, true);
70             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
71             this.SetStyle(ControlStyles.UserPaint, true);
72             this.SetStyle(ControlStyles.Opaque, true);
73
74             this.render = new D2DTextRender(this);
75             this.Document = new Document();
76             this.Document.LayoutLines.Render = this.render;
77             this.View = new EditView(this.Document, this.render, new FooEditEngine.Padding(5, 5, 5, 5));
78             this.View.SrcChanged += View_SrcChanged;
79             
80             this.Controller = new Controller(this.Document, this.View);
81             this.Controller.SelectionChanged += new EventHandler(Controller_CaretMoved);
82
83             this.Ime = new WinIME(this);
84             this.Ime.ImeCompstion += new ImeCompstionEventHandeler(Ime_ImeCompstion);
85             this.Ime.StartCompstion += new StartCompstionEventHandeler(Ime_StartCompstion);
86             this.Ime.EndCompstion += new EndCompstionEventHandeler(Ime_EndCompstion);
87             this.Ime.ImeDocumentFeed += new ImeDocumentFeedEventHandler(Ime_ImeDocumentFeed);
88             this.Ime.ImeReconvert += new ImeReconvertStringEventHandler(Ime_ImeReconvert);
89             this.Ime.ImeQueryReconvert += new ImeQueryReconvertStringEventHandler(Ime_ImeQueryReconvert);
90
91             this.Timer = new System.Windows.Forms.Timer();
92             this.Timer.Tick += new EventHandler(this.Timer_Tick);
93             this.Timer.Interval = Interval;
94             this.SetSystemParamaters();
95
96             this.TabStopChange += new TabStopChangeEventHandler((s, e) => { });
97             this.InsetModeChange += new InsertModeChangeEventHandler((s, e) => { });
98             this.SelectionChanged +=new EventHandler((s,e)=>{});
99
100             this.RightToLeftChanged += FooTextBox_RightToLeftChanged;
101
102             SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(SystemEvents_UserPreferenceChanged);
103
104         }
105
106         /// <summary>
107         /// キャレットが移動したときに通知されるイベント
108         /// </summary>
109         public event EventHandler SelectionChanged;
110
111         /// <summary>
112         /// タブの幅が変更された時に発生するイベント
113         /// </summary>
114         public event TabStopChangeEventHandler TabStopChange;
115
116         /// <summary>
117         /// InsertModeが変更されたときに呼び出されるイベント
118         /// </summary>
119         public event InsertModeChangeEventHandler InsetModeChange;
120
121         /// <summary>
122         /// インデントモードを表す
123         /// </summary>
124         [DefaultValue(IndentMode.Tab)]
125         public IndentMode IndentMode
126         {
127             get
128             {
129                 return this.Controller.IndentMode;
130             }
131             set
132             {
133                 this.Controller.IndentMode = value;
134             }
135         }
136
137         /// <summary>
138         /// テキスト描写に使用するアンチエイリアシングモードを表す
139         /// </summary>
140         [BrowsableAttribute(false)]
141         public TextAntialiasMode TextAntialiasMode
142         {
143             get
144             {
145                 return this.render.TextAntialiasMode;
146             }
147             set
148             {
149                 this.render.TextAntialiasMode = value;
150             }
151         }
152
153         /// <summary>
154         /// マーカーパターンセットを表す
155         /// </summary>
156         [BrowsableAttribute(false)]
157         public MarkerPatternSet MarkerPatternSet
158         {
159             get
160             {
161                 return this.Document.MarkerPatternSet;
162             }
163         }
164
165         /// <summary>
166         /// 保持しているドキュメント
167         /// </summary>
168         [BrowsableAttribute(false)]
169         public Document Document
170         {
171             get;
172             private set;
173         }
174
175         /// <summary>
176         /// 保持しているレイアウト行
177         /// </summary>
178         [BrowsableAttribute(false)]
179         public LineToIndexTable LayoutLines
180         {
181             get { return this.View.LayoutLines; }
182         }
183
184         /// <summary>
185         /// シンタックスハイライター
186         /// </summary>
187         [BrowsableAttribute(false)]
188         public IHilighter Hilighter
189         {
190             get { return this.View.Hilighter; }
191             set { this.View.Hilighter = value; this.View.LayoutLines.ClearLayoutCache(); }
192         }
193
194         /// <summary>
195         /// フォールティングを作成するインターフェイスを表す
196         /// </summary>
197         [BrowsableAttribute(false)]
198         public IFoldingStrategy FoldingStrategy
199         {
200             get
201             {
202                 return this.View.LayoutLines.FoldingStrategy;
203             }
204             set
205             {
206                 this.View.LayoutLines.FoldingStrategy = value;
207                 if (value == null)
208                     this.View.LayoutLines.FoldingCollection.Clear();
209             }
210         }
211
212         /// <summary>
213         /// 境界線のスタイルを指定します
214         /// </summary>
215         public BorderStyle BorderStyle
216         {
217             get { return this._BoderStyle; }
218             set { this._BoderStyle = value; this.UpdateStyles(); }
219         }
220
221
222         /// <summary>
223         /// 行番号を表示するかどうか
224         /// </summary>
225         [DefaultValue(false)]
226         public bool DrawLineNumber
227         {
228             get
229             {
230                 return this.Document.DrawLineNumber;
231             }
232             set
233             {
234                 this.Document.DrawLineNumber = value;
235                 this.JumpCaret(this.CaretPostion.row,this.CaretPostion.col);
236             }
237         }
238         
239         /// <summary>
240         /// ルーラーを表示するかどうか
241         /// </summary>
242         [DefaultValue(false)]
243         public bool DrawRuler
244         {
245             get
246             {
247                 return !this.Document.HideRuler;
248             }
249             set
250             {
251                 this.Document.HideRuler = !value;
252                 this.JumpCaret(this.CaretPostion.row, this.CaretPostion.col);
253             }
254         }
255
256         /// <summary>
257         /// 桁折りを行う方法を指定する
258         /// </summary>
259         /// <remarks>
260         /// 反映させるためにはレイアウト行の再構築を行う必要があります
261         /// </remarks>
262         [DefaultValue(LineBreakMethod.None)]
263         public LineBreakMethod LineBreakMethod
264         {
265             get
266             {
267                 return this.Document.LineBreak;
268             }
269             set
270             {
271                 this.Document.LineBreak = value;
272             }
273         }
274
275         /// <summary>
276         /// 桁折り時の文字数を指定する。
277         /// </summary>
278         /// <remarks>
279         /// 反映させるためにはレイアウト行の再構築を行う必要があります
280         /// </remarks>
281         [DefaultValue(80)]
282         public int LineBreakCharCount
283         {
284             get
285             {
286                 return this.Document.LineBreakCharCount;
287             }
288             set
289             {
290                 this.Document.LineBreakCharCount = value;
291             }
292         }
293
294         /// <summary>
295         /// URLをマークするかどうか
296         /// </summary>
297         [DefaultValue(false)]
298         public bool UrlMark
299         {
300             get
301             {
302                 return this.Document.UrlMark;
303             }
304             set
305             {
306                 this.Document.UrlMark = value;
307             }
308         }
309
310         /// <summary>
311         /// タブストップの幅
312         /// </summary>
313         [DefaultValue(4)]
314         public int TabStops
315         {
316             get { return this.Document.TabStops; }
317             set {
318                 this.Document.TabStops = value;
319                 this.View.AdjustCaretAndSrc();
320                 this.TabStopChange(this, null);
321             }
322         }
323
324         /// <summary>
325         /// 全角スペースを表示するなら真。そうでないなら偽
326         /// </summary>
327         [DefaultValue(false)]
328         public bool ShowFullSpace
329         {
330             get
331             {
332                 return this.Document.ShowFullSpace;
333             }
334             set
335             {
336                 this.Document.ShowFullSpace = value;
337             }
338         }
339
340         /// <summary>
341         /// 半角スペースを表示するなら真。そうでないなら偽
342         /// </summary>
343         [DefaultValue(false)]
344         public bool ShowHalfSpace
345         {
346             get
347             {
348                 return this.Document.ShowHalfSpace;
349             }
350             set
351             {
352                 this.Document.ShowHalfSpace = value;
353             }
354         }
355
356         /// <summary>
357         /// タブを表示するなら真。そうでないなら偽
358         /// </summary>
359         [DefaultValue(false)]
360         public bool ShowTab
361         {
362             get
363             {
364                 return this.Document.ShowTab;
365             }
366             set
367             {
368                 this.Document.ShowTab = value;
369             }
370         }
371
372         /// <summary>
373         /// 改行マークを表示するなら真。そうでないなら偽
374         /// </summary>
375         [DefaultValue(false)]
376         public bool ShowLineBreak
377         {
378             get
379             {
380                 return this.Document.ShowLineBreak;
381             }
382             set
383             {
384                 this.Document.ShowLineBreak = value;
385             }
386         }
387
388         /// <summary>
389         /// 選択中の文字列
390         /// </summary>
391         /// <remarks>
392         /// 未選択状態で文字列を代入した場合、キャレット位置に挿入され、そうでないときは置き換えられます。
393         /// </remarks>
394         [BrowsableAttribute(false)]
395         public string SelectedText
396         {
397             get { return this.Controller.SelectedText; }
398             set { this.Controller.SelectedText = value; }
399         }
400
401         /// <summary>
402         /// キャレット位置を表す
403         /// </summary>
404         [BrowsableAttribute(false)]
405         public TextPoint CaretPostion
406         {
407             get { return this.Document.CaretPostion; }
408         }
409
410         /// <summary>
411         /// 選択範囲を表す
412         /// </summary>
413         /// <remarks>
414         /// Lengthが0の場合はキャレット位置を表します
415         /// 矩形選択モードの場合、選択範囲の文字数ではなく、開始位置から終了位置までの長さとなります
416         /// </remarks>
417         [BrowsableAttribute(false)]
418         public TextRange Selection
419         {
420             get { return new TextRange(this.Controller.SelectionStart,this.Controller.SelectionLength); }
421             set
422             {
423                 this.Controller.Select(value.Index, value.Length);
424             }
425         }
426
427         /// <summary>
428         /// 挿入モードかどうか
429         /// </summary>
430         [DefaultValue(true)]
431         public bool InsertMode
432         {
433             get { return this.View.InsertMode; }
434             set
435             {
436                 this.View.InsertMode = value;
437                 this.InsetModeChange(this, null);
438             }
439         }
440
441         /// <summary>
442         /// 矩形選択を行うかどうか
443         /// </summary>
444         [DefaultValue(false)]
445         public bool RectSelection
446         {
447             get { return this.Controller.RectSelection; }
448             set { this.Controller.RectSelection = value; }
449         }
450
451         System.Drawing.Color ForegroundColor = SystemColors.ControlText,
452             BackgroundColor = SystemColors.Control,
453             HilightColor = System.Drawing.Color.DeepSkyBlue,
454             Keyword1Color = System.Drawing.Color.Blue,
455             Keyword2Color = System.Drawing.Color.DarkCyan,
456             LiteralColor = System.Drawing.Color.Brown,
457             UrlColor = System.Drawing.Color.Blue,
458             ControlCharColor = System.Drawing.Color.Gray,
459             CommentColor = System.Drawing.Color.Green,
460             InsertCaretColor = System.Drawing.Color.Black,
461             OverwriteCaretColor = System.Drawing.Color.Black,
462             LineMarkerColor = System.Drawing.Color.WhiteSmoke,
463             UpdateAreaColor = System.Drawing.Color.MediumSeaGreen,
464             LineNumberColor = System.Drawing.Color.DimGray;
465
466         /// <summary>
467         /// 前景色
468         /// </summary>
469         public System.Drawing.Color Foreground
470         {
471             get
472             {
473                 return this.ForegroundColor;
474             }
475             set
476             {
477                 this.render.Foreground = D2DTextRender.ToColor4(value);
478                 this.ForegroundColor = value;
479             }
480         }
481
482         /// <summary>
483         /// 背景色
484         /// </summary>
485         public System.Drawing.Color Background
486         {
487             get
488             {
489                 return this.BackgroundColor;
490             }
491             set
492             {
493                 this.render.Background = D2DTextRender.ToColor4(value);
494                 this.BackgroundColor = value;
495             }
496         }
497
498         /// <summary>
499         /// 挿入モード時のキャレット色
500         /// </summary>
501         public System.Drawing.Color InsertCaret
502         {
503             get
504             {
505                 return this.InsertCaretColor;
506             }
507             set
508             {
509                 this.InsertCaretColor = value;
510                 this.render.InsertCaret = D2DTextRender.ToColor4(value);
511             }
512         }
513
514         /// <summary>
515         /// 上書きモード時のキャレット色
516         /// </summary>
517         public System.Drawing.Color OverwriteCaret
518         {
519             get
520             {
521                 return this.OverwriteCaretColor;
522             }
523             set
524             {
525                 this.OverwriteCaretColor = value;
526                 this.render.OverwriteCaret = D2DTextRender.ToColor4(value);
527             }
528         }
529
530         /// <summary>
531         /// ラインマーカーの色
532         /// </summary>
533         public System.Drawing.Color LineMarker
534         {
535             get
536             {
537                 return this.LineMarkerColor;
538             }
539             set
540             {
541                 this.LineMarkerColor = value;
542                 this.render.LineMarker = D2DTextRender.ToColor4(value);
543             }
544         }
545
546         /// <summary>
547         /// コントロールの色
548         /// </summary>
549         public System.Drawing.Color ControlChar
550         {
551             get
552             {
553                 return this.ControlCharColor;
554             }
555             set
556             {
557                 this.ControlCharColor = value;
558                 this.render.ControlChar = D2DTextRender.ToColor4(value);
559             }
560         }
561
562         /// <summary>
563         /// 編集行フラグの色
564         /// </summary>
565         public System.Drawing.Color UpdateArea
566         {
567             get
568             {
569                 return this.UpdateAreaColor;
570             }
571             set
572             {
573                 this.UpdateAreaColor = value;
574                 this.render.UpdateArea = D2DTextRender.ToColor4(value);
575             }
576         }
577
578         /// <summary>
579         /// 行番号の色
580         /// </summary>
581         public System.Drawing.Color LineNumber
582         {
583             get
584             {
585                 return this.LineNumber;
586             }
587             set
588             {
589                 this.LineNumber = value;
590                 this.render.LineNumber = D2DTextRender.ToColor4(value);
591             }
592         }
593
594         /// <summary>
595         /// URLの色
596         /// </summary>
597         public System.Drawing.Color Url
598         {
599             get
600             {
601                 return this.UrlColor;
602             }
603             set
604             {
605                 this.UrlColor = value;
606                 this.render.Url = D2DTextRender.ToColor4(value);
607             }
608         }
609
610         /// <summary>
611         /// 選択領域の色
612         /// </summary>
613         public System.Drawing.Color Hilight
614         {
615             get
616             {
617                 return this.HilightColor;
618             }
619             set
620             {
621                 this.HilightColor = value;
622                 this.render.Hilight = D2DTextRender.ToColor4(value);
623             }
624         }
625
626         /// <summary>
627         /// コメントの色
628         /// </summary>
629         public System.Drawing.Color Comment
630         {
631             get
632             {
633                 return this.CommentColor;
634             }
635             set
636             {
637                 this.CommentColor = value;
638                 this.render.Comment = D2DTextRender.ToColor4(value);
639             }
640         }
641
642         /// <summary>
643         /// 文字リテラルの色
644         /// </summary>
645         public System.Drawing.Color Literal
646         {
647             get
648             {
649                 return this.LiteralColor;
650             }
651             set
652             {
653                 this.LiteralColor = value;
654                 this.render.Literal = D2DTextRender.ToColor4(value);
655             }
656         }
657
658         /// <summary>
659         /// キーワード1の色
660         /// </summary>
661         public System.Drawing.Color Keyword1
662         {
663             get
664             {
665                 return this.Keyword1Color;
666             }
667             set
668             {
669                 this.Keyword1Color = value;
670                 this.render.Keyword1 = D2DTextRender.ToColor4(value);
671             }
672         }
673
674         /// <summary>
675         /// キーワード2の色
676         /// </summary>
677         public System.Drawing.Color Keyword2
678         {
679             get
680             {
681                 return this.Keyword2Color;
682             }
683             set
684             {
685                 this.Keyword2Color = value;
686                 this.render.Keyword2 = D2DTextRender.ToColor4(value);
687             }
688         }
689
690         /// <summary>
691         /// キャレットに下線を描くかどうか
692         /// </summary>
693         [DefaultValue(false)]
694         public bool DrawCaretLine
695         {
696             get { return !this.View.HideLineMarker; }
697             set { this.View.HideLineMarker = !value; }
698         }
699
700         /// <summary>
701         /// ドキュメントを選択する
702         /// </summary>
703         /// <param name="start">開始インデックス</param>
704         /// <param name="length">長さ</param>
705         public void Select(int start, int length)
706         {
707             this.Controller.Select(start, length);
708             this.HScrollBar.Value = (int)this.View.Src.X;
709             this.VScrollBar.Value = this.View.Src.Row;
710         }
711
712         /// <summary>
713         /// ドキュメント全体を選択する
714         /// </summary>
715         public void SelectAll()
716         {
717             this.Controller.Select(0, this.Document.Length - 1);
718         }
719
720         /// <summary>
721         /// 選択を解除する
722         /// </summary>
723         public void DeSelectAll()
724         {
725             this.Controller.DeSelectAll();
726         }
727
728         /// <summary>
729         /// クリップボードにコピーする
730         /// </summary>
731         public void Copy()
732         {
733             string text = this.SelectedText;
734             if(text != null && text != string.Empty)
735                 Clipboard.SetText(text);
736         }
737
738         /// <summary>
739         /// クリップボードにコピーし、指定した範囲にある文字列をすべて削除します
740         /// </summary>
741         public void Cut()
742         {
743             string text = this.SelectedText;
744             if (text != null && text != string.Empty)
745             {
746                 Clipboard.SetText(text);
747                 this.Controller.SelectedText = "";
748             }
749         }
750
751         /// <summary>
752         /// クリップボードの内容をペーストします
753         /// </summary>
754         public void Paste()
755         {
756             if (Clipboard.ContainsText() == false)
757                 return;
758             this.Controller.SelectedText = Clipboard.GetText();
759         }
760
761         /// <summary>
762         /// キャレットを指定した行に移動させます
763         /// </summary>
764         /// <param name="index">インデックス</param>
765         /// <remarks>このメソッドを呼び出すと選択状態は解除されます</remarks>
766         public void JumpCaret(int index)
767         {
768             this.Controller.JumpCaret(index);
769         }
770         /// <summary>
771         /// キャレットを指定した行と桁に移動させます
772         /// </summary>
773         /// <param name="row">行番号</param>
774         /// <param name="col">桁</param>
775         /// <remarks>このメソッドを呼び出すと選択状態は解除されます</remarks>
776         public void JumpCaret(int row, int col)
777         {
778             this.Controller.JumpCaret(row, col);
779         }
780
781         /// <summary>
782         /// 再描写します
783         /// </summary>
784         public new void Refresh()
785         {
786             if (this.Document.FireUpdateEvent == false)
787                 throw new InvalidOperationException("");
788             if(this.View.CaretBlink)
789                 this.View.CaretBlink = true;
790             this.Invalidate();
791             this.Update();
792         }
793
794         /// <summary>
795         /// 行の高さを取得する
796         /// </summary>
797         /// <param name="row">行</param>
798         /// <returns>高さ</returns>
799         public double GetLineHeight(int row)
800         {
801             if (this.Document.FireUpdateEvent == false)
802                 throw new InvalidOperationException("");
803             return this.View.LayoutLines.GetLayout(row).Height;
804         }
805
806         /// <summary>
807         /// 対応する座標を返す
808         /// </summary>
809         /// <param name="tp">テキストポイント</param>
810         /// <returns>座標</returns>
811         /// <remarks>テキストポイントがクライアント領域の原点より外にある場合、返される値は原点に丸められます</remarks>
812         public System.Drawing.Point GetPostionFromTextPoint(TextPoint tp)
813         {
814             if (this.Document.FireUpdateEvent == false)
815                 throw new InvalidOperationException("");
816             return this.View.GetPostionFromTextPoint(tp);
817         }
818
819         /// <summary>
820         /// 対応するテキストポイントを返す
821         /// </summary>
822         /// <param name="p">クライアント領域の原点を左上とする座標</param>
823         /// <returns>テキストポイント</returns>
824         public TextPoint GetTextPointFromPostion(System.Drawing.Point p)
825         {
826             if (this.Document.FireUpdateEvent == false)
827                 throw new InvalidOperationException("");
828             return this.View.GetTextPointFromPostion(p);
829         }
830
831         /// <summary>
832         /// インデックスに対応する座標を得ます
833         /// </summary>
834         /// <param name="index">インデックス</param>
835         /// <returns>座標を返す</returns>
836         public System.Drawing.Point GetPostionFromIndex(int index)
837         {
838             if (this.Document.FireUpdateEvent == false)
839                 throw new InvalidOperationException("");
840             TextPoint tp = this.View.GetLayoutLineFromIndex(index);
841             return this.View.GetPostionFromTextPoint(tp);
842         }
843
844         /// <summary>
845         /// 座標からインデックスに変換します
846         /// </summary>
847         /// <param name="p">座標</param>
848         /// <returns>インデックスを返す</returns>
849         public int GetIndexFromPostion(System.Drawing.Point p)
850         {
851             if (this.Document.FireUpdateEvent == false)
852                 throw new InvalidOperationException("");
853             TextPoint tp = this.View.GetTextPointFromPostion(p);
854             return this.View.GetIndexFromLayoutLine(tp);
855         }
856
857         /// <summary>
858         /// レイアウト行をすべて破棄し、再度レイアウトを行う
859         /// </summary>
860         public void PerfomLayouts()
861         {
862             this.View.PerfomLayouts();
863             initScrollBars();
864         }
865
866         /// <summary>
867         /// ストリームからドキュメントを構築する
868         /// </summary>
869         /// <param name="tr">TextReader</param>
870         /// <param name="token">キャンセル用トークン</param>
871         /// <returns>Taskオブジェクト</returns>
872         public async Task LoadAsync(System.IO.TextReader tr, System.Threading.CancellationTokenSource token)
873         {
874             WinFileReader fs = new WinFileReader(tr);
875             await this.LoadAsyncImpl(fs, token);
876         }
877
878         /// <summary>
879         /// ファイルからドキュメントを構築する
880         /// </summary>
881         /// <param name="filepath">ファイルパス</param>
882         /// <param name="enc">エンコード</param>
883         /// <param name="token">キャンセル用トークン</param>
884         /// <returns>Taskオブジェクト</returns>
885         public async Task LoadFileAsync(string filepath, Encoding enc, System.Threading.CancellationTokenSource token)
886         {
887             WinFileReader fs = new WinFileReader(filepath, enc);
888             await this.LoadAsyncImpl(fs, token);
889             fs.Close();
890         }
891
892         async Task LoadAsyncImpl(WinFileReader fs, System.Threading.CancellationTokenSource token)
893         {
894             this.Enabled = false;
895             this.View.LayoutLines.IsFrozneDirtyFlag = true;
896             await this.Document.LoadAsync(fs, token);
897             this.View.LayoutLines.IsFrozneDirtyFlag = false;
898             this.initScrollBars();
899             this.OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, MousePosition.X, MousePosition.Y, 0));
900             this.View.CalculateLineCountOnScreen();
901             this.Enabled = true;
902         }
903
904         /// <summary>
905         /// ドキュメントの内容をファイルに保存する
906         /// </summary>
907         /// <param name="filepath">ファイルパス</param>
908         /// <param name="newLine">改行コード</param>
909         /// <param name="enc">エンコード</param>
910         /// <returns>Taskオブジェクト</returns>
911         public async Task SaveFile(string filepath, Encoding enc, string newLine, System.Threading.CancellationTokenSource token)
912         {
913             WinFileWriter fs = new WinFileWriter(filepath, enc);
914             fs.NewLine = newLine;
915             await this.Document.SaveAsync(fs, token);
916             fs.Close();
917         }
918
919         /// <summary>
920         /// マウスカーソルを指定します
921         /// </summary>
922         public override Cursor Cursor
923         {
924             get
925             {
926                 return base.Cursor;
927             }
928             set
929             {
930                 base.Cursor = value;
931                 this.VScrollBar.Cursor = DefaultCursor;
932                 this.HScrollBar.Cursor = DefaultCursor;
933             }
934         }
935
936         private const int WS_BORDER = 0x00800000;
937         private const int WS_EX_CLIENTEDGE = 0x00000200;
938         /// <summary>
939         /// コントロールの外観を指定します
940         /// </summary>
941         protected override CreateParams CreateParams
942         {
943             get
944             {
945                 CreateParams cp = base.CreateParams;
946                 switch (this.BorderStyle)
947                 {
948                     case BorderStyle.Fixed3D:
949                         cp.ExStyle |= WS_EX_CLIENTEDGE;
950                         break;
951                     case BorderStyle.FixedSingle:
952                         cp.Style |= WS_BORDER;
953                         break;
954                 }
955                 return cp;
956             }
957         }
958
959         /// <summary>
960         /// コマンド キーを処理します
961         /// </summary>
962         /// <param name="msg">メッセージ</param>
963         /// <param name="keyData">キーデータ</param>
964         /// <returns>文字がコントロールによって処理された場合は true。それ以外の場合は false。 </returns>
965         protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
966         {
967             const int WM_KEYDOWN = 0x100;
968             if (msg.Msg != WM_KEYDOWN)
969                 return base.ProcessCmdKey(ref msg, keyData);
970             switch (keyData)
971             {
972                 case Keys.Control | Keys.C:
973                     this.Copy();
974                     break;
975                 case Keys.Control | Keys.V:
976                     this.Paste();
977                     this.Refresh();
978                     break;
979                 case Keys.Control | Keys.X:
980                     this.Cut();
981                     this.Refresh();
982                     break;
983                 case Keys.Control | Keys.Z:
984                     this.Document.UndoManager.undo();
985                     this.Refresh();
986                     break;
987                 case Keys.Control | Keys.Y:
988                     this.Document.UndoManager.redo();
989                     this.Refresh();
990                     break;
991                 case Keys.Control | Keys.B:
992                     if (this.Controller.RectSelection)
993                         this.Controller.RectSelection = false;
994                     else
995                         this.Controller.RectSelection = true;
996                     break;
997                 default:
998                     return base.ProcessCmdKey(ref msg,keyData);
999             }
1000             return true;
1001         }
1002
1003         /// <summary>
1004         /// インスタンスを破棄します
1005         /// </summary>
1006         /// <param name="disposing">マネージ リソースとアンマネージ リソースの両方を解放する場合は true。アンマネージ リソースだけを解放する場合は false。</param>
1007         protected override void Dispose(bool disposing)
1008         {
1009             SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.SystemEvents_UserPreferenceChanged);
1010             this.render.Dispose();
1011             this.Timer.Dispose();
1012             base.Dispose(disposing);
1013         }
1014
1015         /// <summary>
1016         /// 入力可能な文字かチェックします
1017         /// </summary>
1018         /// <param name="charCode">入力しようとした文字</param>
1019         /// <returns>可能なら真。そうでなければ偽</returns>
1020         protected override bool IsInputChar(char charCode)
1021         {
1022             if ((0x20 <= charCode && charCode <= 0x7e)
1023                 || charCode == '\r'
1024                 || charCode == '\n'
1025                 || charCode == ' '
1026                 || charCode == '\t'
1027                 || charCode == ' '
1028                 || 0x7f < charCode)
1029             {
1030                 return true;
1031             }
1032
1033             return false;
1034         }
1035
1036         /// <summary>
1037         /// PaddingChangedイベントを発生させます
1038         /// </summary>
1039         /// <param name="e">インベントデータ</param>
1040         protected override void OnPaddingChanged(EventArgs e)
1041         {
1042             base.OnPaddingChanged(e);
1043             this.View.Padding = new Padding(this.Padding.Left, this.Padding.Top, this.Padding.Right, this.Padding.Bottom);
1044         }
1045
1046         /// <summary>
1047         /// GotFocusイベントを発生させます
1048         /// </summary>
1049         /// <param name="e">インベントデータ</param>
1050         protected override void OnGotFocus(EventArgs e)
1051         {
1052             base.OnGotFocus(e);
1053             this.View.IsFocused = true;
1054             this.Refresh();
1055         }
1056
1057         /// <summary>
1058         /// LostFocusイベントを発生させます
1059         /// </summary>
1060         /// <param name="e">インベントデータ</param>
1061         protected override void OnLostFocus(EventArgs e)
1062         {
1063             base.OnLostFocus(e);
1064             this.View.IsFocused = false;
1065             this.Refresh();
1066         }
1067
1068         /// <summary>
1069         /// FontChangedイベントを発生させます
1070         /// </summary>
1071         /// <param name="e">インベントデータ</param>
1072         protected override void OnFontChanged(EventArgs e)
1073         {
1074             if (this.DesignMode)
1075                 return;
1076             base.OnFontChanged(e);
1077             initScrollBars();
1078         }
1079
1080         /// <summary>
1081         /// MouseDownイベントを発生させます
1082         /// </summary>
1083         /// <param name="e">インベントデータ</param>
1084         protected override void OnMouseDown(MouseEventArgs e)
1085         {
1086             TextPoint tp = this.View.GetTextPointFromPostion(e.Location);
1087             if (tp == TextPoint.Null)
1088                 return;
1089             int index = this.View.LayoutLines.GetIndexFromTextPoint(tp);
1090             
1091             FooMouseEventArgs mouseEvent = new FooMouseEventArgs(index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
1092             
1093             base.OnMouseDown(mouseEvent);
1094             
1095             if (mouseEvent.Handled)
1096                 return;
1097
1098             if (e.Button == MouseButtons.Left)
1099             {
1100                 FoldingItem foldingData = this.View.HitFoldingData(e.Location.X, tp.row);
1101                 if (foldingData != null)
1102                 {
1103                     if (foldingData.Expand)
1104                         this.View.LayoutLines.FoldingCollection.Collapse(foldingData);
1105                     else
1106                         this.View.LayoutLines.FoldingCollection.Expand(foldingData);
1107                     this.Controller.JumpCaret(foldingData.Start, false);
1108                 }
1109                 else
1110                 {
1111                     this.Controller.JumpCaret(tp.row, tp.col, false);
1112                 }
1113                 this.View.IsFocused = true;
1114                 this.Focus();
1115                 this.Refresh();
1116             }
1117         }
1118
1119         /// <summary>
1120         /// MouseClickイベントを発生させます
1121         /// </summary>
1122         /// <param name="e">インベントデータ</param>
1123         protected override void OnMouseClick(MouseEventArgs e)
1124         {
1125             int index = this.GetIndexFromPostion(e.Location);
1126
1127             FooMouseEventArgs mouseEvent = new FooMouseEventArgs(index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
1128
1129             base.OnMouseClick(mouseEvent);
1130         }
1131
1132         /// <summary>
1133         /// MouseDoubleClickイベントを発生させます
1134         /// </summary>
1135         /// <param name="e">インベントデータ</param>
1136         protected override void OnMouseDoubleClick(MouseEventArgs e)
1137         {
1138             TextPoint tp = this.View.GetTextPointFromPostion(e.Location);
1139             if (tp == TextPoint.Null)
1140                 return;
1141             int index = this.View.LayoutLines.GetIndexFromTextPoint(tp);
1142
1143             FooMouseEventArgs mouseEvent = new FooMouseEventArgs(index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
1144             
1145             base.OnMouseDoubleClick(mouseEvent);
1146
1147             if (mouseEvent.Handled)
1148                 return;
1149
1150             this.Controller.SelectWord(index);
1151             
1152             this.Refresh();
1153         }
1154
1155         /// <summary>
1156         /// MouseMoveイベントを発生させます
1157         /// </summary>
1158         /// <param name="e">インベントデータ</param>
1159         protected override void OnMouseMove(MouseEventArgs e)
1160         {
1161             if (this.Focused == false)
1162                 return;
1163
1164             base.OnMouseMove(e);
1165
1166             if (this.View.HitTextArea(e.Location.X, e.Location.Y))
1167             {
1168                 TextPoint tp = this.View.GetTextPointFromPostion(e.Location);
1169                 if (this.Controller.IsMarker(tp, HilightType.Url))
1170                     this.Cursor = Cursors.Hand;
1171                 else
1172                     this.Cursor = Cursors.IBeam;
1173
1174                 if (e.Button == MouseButtons.Left)
1175                 {
1176                     this.Controller.MoveCaretAndSelect(tp);
1177                     this.Refresh();
1178                 }
1179             }
1180             else
1181             {
1182                 this.Cursor = Cursors.Arrow;
1183             }
1184         }
1185
1186         /// <summary>
1187         /// MouseWheelイベントを発生させます
1188         /// </summary>
1189         /// <param name="e">インベントデータ</param>
1190         protected override void OnMouseWheel(MouseEventArgs e)
1191         {
1192             base.OnMouseWheel(e);
1193
1194             ScrollDirection dir = e.Delta > 0 ? ScrollDirection.Up : ScrollDirection.Down;
1195             this.Controller.Scroll(dir, SystemInformation.MouseWheelScrollLines, false, false);
1196             this.Refresh();
1197         }
1198
1199         /// <summary>
1200         /// Paintイベントを発生させます
1201         /// </summary>
1202         /// <param name="e">インベントデータ</param>
1203         protected override void OnPaint(PaintEventArgs e)
1204         {
1205             if (DesignMode)
1206             {
1207                 SolidBrush brush = new SolidBrush(this.BackColor);
1208                 e.Graphics.FillRectangle(brush, this.ClientRectangle);
1209                 brush.Dispose();
1210             }else if (this.Document.FireUpdateEvent){
1211                 this.render.BegineDraw();
1212                 this.View.Draw(e.ClipRectangle);
1213                 this.render.EndDraw();
1214             }
1215             base.OnPaint(e);
1216         }
1217
1218         /// <summary>
1219         /// PaintBackgroundイベントを発生させます
1220         /// </summary>
1221         /// <param name="e">インベントデータ</param>
1222         protected override void OnPaintBackground(PaintEventArgs e)
1223         {
1224         }
1225
1226         /// <summary>
1227         /// PreviewKeyDownイベントを発生させます
1228         /// </summary>
1229         /// <param name="e">インベントデータ</param>
1230         protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
1231         {
1232             base.OnPreviewKeyDown(e);
1233             switch (e.KeyCode)
1234             {
1235                 case Keys.Up:
1236                 case Keys.Down:
1237                 case Keys.Left:
1238                 case Keys.Right:
1239                 case Keys.Tab:
1240                     e.IsInputKey = true;
1241                     break;
1242             }
1243         }
1244
1245         /// <summary>
1246         /// KeyDownイベントを発生させます
1247         /// </summary>
1248         /// <param name="e">インベントデータ</param>
1249         protected override void OnKeyDown(KeyEventArgs e)
1250         {
1251             base.OnKeyDown(e);
1252             
1253             if (e.Handled)
1254                 return;
1255
1256             switch (e.KeyCode)
1257             {
1258                 case Keys.Up:
1259                     this.Controller.MoveCaretVertical(-1, e.Shift);
1260                     this.Refresh();
1261                     break;
1262                 case Keys.Down:
1263                     this.Controller.MoveCaretVertical(+1, e.Shift);
1264                     this.Refresh();
1265                     break;
1266                 case Keys.Left:
1267                     this.Controller.MoveCaretHorizontical(-1, e.Shift, e.Control);
1268                     this.Refresh();
1269                     break;
1270                 case Keys.Right:
1271                     this.Controller.MoveCaretHorizontical(1, e.Shift, e.Control);
1272                     this.Refresh();
1273                     break;
1274                 case Keys.PageUp:
1275                     this.Controller.Scroll(ScrollDirection.Up, this.VScrollBar.LargeChange,e.Shift,true);
1276                     this.Refresh();
1277                     break;
1278                 case Keys.PageDown:
1279                     this.Controller.Scroll(ScrollDirection.Down, this.VScrollBar.LargeChange,e.Shift,true);
1280                     this.Refresh();
1281                     break;
1282                 case Keys.Insert:
1283                     if (this.InsertMode)
1284                         this.InsertMode = false;
1285                     else
1286                         this.InsertMode = true;
1287                     break;
1288                 case Keys.Delete:
1289                     this.Controller.DoDeleteAction();
1290                     this.Refresh();
1291                     break;
1292                 case Keys.Back:
1293                     this.Controller.DoBackSpaceAction();
1294                     this.Refresh();
1295                     break;
1296                 case Keys.Home:
1297                     if (e.Control)
1298                         this.Controller.JumpToHead(e.Shift);
1299                     else
1300                         this.Controller.JumpToLineHead(this.Document.CaretPostion.row, e.Shift);
1301                     this.Refresh();
1302                     break;
1303                 case Keys.End:
1304                     if (e.Control)
1305                         this.Controller.JumpToEnd(e.Shift);
1306                     else
1307                         this.Controller.JumpToLineEnd(this.Document.CaretPostion.row, e.Shift);
1308                     this.Refresh();
1309                     break;
1310                 case Keys.Tab:
1311                     if (this.Controller.SelectionLength == 0)
1312                         this.Controller.DoInputChar('\t');
1313                     else if (e.Shift)
1314                         this.Controller.DownIndent();
1315                     else
1316                         this.Controller.UpIndent();
1317                     this.Refresh();
1318                     break;
1319             }
1320         }
1321
1322         /// <summary>
1323         /// KeyPressイベントを発生させます
1324         /// </summary>
1325         /// <param name="e">インベントデータ</param>
1326         protected override void OnKeyPress(KeyPressEventArgs e)
1327         {
1328             base.OnKeyPress(e);
1329
1330             if (e.Handled)
1331                 return;
1332             
1333             switch (e.KeyChar)
1334             {
1335                 case '\r':
1336                     this.Controller.DoEnterAction();
1337                     this.Refresh();
1338                     break;
1339                 case '\t':
1340                     break;  //OnKeyDownで処理しているので不要
1341                 default:
1342                     if (IsInputChar(e.KeyChar) == false)
1343                         break;
1344                     this.Controller.DoInputChar(e.KeyChar);
1345                     this.Refresh();
1346                     break;
1347             }
1348         }
1349
1350         /// <summary>
1351         /// ClientSizeChangedイベントを発生させます
1352         /// </summary>
1353         /// <param name="e">インベントデータ</param>
1354         protected override void OnClientSizeChanged(EventArgs e)
1355         {
1356             if (this.DesignMode)
1357                 return;
1358             base.OnClientSizeChanged(e);
1359             
1360             this.View.PageBound = new Rectangle(0,
1361                 0,
1362                 Math.Max(this.ClientRectangle.Width - this.VScrollBar.Width,0),
1363                 Math.Max(this.ClientRectangle.Height - this.HScrollBar.Height, 0));
1364
1365             initScrollBars();
1366             this.Refresh();
1367         }
1368
1369         void View_SrcChanged(object sender, EventArgs e)
1370         {
1371             if (this.View.Src.Row > this.VScrollBar.Maximum)
1372                 this.VScrollBar.Maximum = this.View.Src.Row + this.View.LineCountOnScreen + 1;
1373
1374             int srcX = (int)Math.Abs(this.View.Src.X);
1375             if (srcX > this.HScrollBar.Maximum)
1376                 this.HScrollBar.Maximum = srcX + (int)this.View.PageBound.Width + 1;
1377
1378             this.HScrollBar.Value = srcX;
1379
1380             this.VScrollBar.Value = this.View.Src.Row;
1381         }
1382
1383         void FooTextBox_RightToLeftChanged(object sender, EventArgs e)
1384         {
1385             this.Document.RightToLeft = this.RightToLeft == System.Windows.Forms.RightToLeft.Yes;
1386         }
1387
1388         void VScrollBar_Scroll(object sender, ScrollEventArgs e)
1389         {
1390             this.View.TryScroll(this.View.Src.X, e.NewValue);
1391             this.Refresh();
1392         }
1393
1394         void HScrollBar_Scroll(object sender, ScrollEventArgs e)
1395         {
1396             int toX;
1397             if (this.RightToLeft == System.Windows.Forms.RightToLeft.Yes)
1398                 toX = -e.NewValue;
1399             else
1400                 toX = e.NewValue;
1401             this.View.TryScroll(toX, this.View.Src.Row);
1402             this.Refresh();
1403         }
1404
1405         void Ime_StartCompstion(object sender, StartCompstionEventArgs e)
1406         {
1407             this.Ime.Font = this.Font;
1408             System.Drawing.Point p = this.GetPostionFromIndex(this.Controller.SelectionStart);
1409             float dpi;
1410             this.render.GetDpi(out dpi, out dpi);
1411             p.X = (int)(p.X * dpi / 96);
1412             p.Y = (int)(p.Y * dpi / 96);
1413             this.Ime.Location = p;
1414             this.View.HideCaret = true;
1415         }
1416
1417         void Ime_EndCompstion(object sender, EndCompstionEventArgs e)
1418         {
1419             this.View.HideCaret = false;
1420         }
1421
1422         void Ime_ImeCompstion(object sender, ImeCompstionEventArgs e)
1423         {
1424             this.Controller.DoInputString(e.InputText);
1425             this.Refresh();
1426         }
1427
1428         void Ime_ImeDocumentFeed(object sender, ImeDocumentFeedEventArgs e)
1429         {
1430             TextPoint tp = this.CaretPostion;
1431             e.Pragraph = this.LayoutLines[tp.row];
1432             e.pos = tp.col;
1433         }
1434
1435         void Ime_ImeReconvert(object sender, ImeReconvertStringEventArgs e)
1436         {
1437             if (this.RectSelection)
1438                 return;
1439             if (this.Controller.SelectionLength == 0)
1440             {
1441                 TextPoint tp = this.LayoutLines.GetTextPointFromIndex(this.Controller.SelectionStart);
1442                 e.TargetString = this.LayoutLines[tp.row];
1443                 e.AutoAdjust = true;
1444             }
1445             else
1446             {
1447                 e.TargetString = this.SelectedText;
1448                 if (e.TargetString.Length > 40)
1449                     e.TargetString.Remove(40);
1450             }
1451             e.CaretPostion = this.View.CaretLocation;
1452         }
1453
1454         void Ime_ImeQueryReconvert(object sender, ImeQueryRecovertStringEventArgs e)
1455         {
1456             TextPoint tp = this.LayoutLines.GetTextPointFromIndex(this.Controller.SelectionStart);
1457             tp.col = e.offset;
1458
1459             int index = this.View.GetIndexFromLayoutLine(tp);
1460
1461             this.Select(index, index + e.length);
1462         }
1463
1464         void Controller_CaretMoved(object sender, EventArgs e)
1465         {
1466             this.SelectionChanged(this, null);
1467         }
1468
1469         void initScrollBars()
1470         {
1471             this.VScrollBar.SmallChange = 1;
1472             this.VScrollBar.LargeChange = this.View.LineCountOnScreen;
1473             this.VScrollBar.Maximum = this.View.LayoutLines.Count + this.View.LineCountOnScreen + 1;
1474             this.HScrollBar.SmallChange = 10;
1475             this.HScrollBar.LargeChange = (int)this.View.PageBound.Width;
1476             this.HScrollBar.Maximum = this.HScrollBar.LargeChange + 1;
1477         }
1478
1479         void Timer_Tick(object sender,EventArgs e)
1480         {
1481             if (this.Document.CaretPostion.row >= this.View.LayoutLines.Count || DesignMode)
1482                 return;
1483
1484             ITextLayout layout = this.View.LayoutLines.GetLayout(this.Document.CaretPostion.row);
1485
1486             Size redrawSize = new Size();
1487             redrawSize.Width = layout.GetWidthFromIndex(this.Document.CaretPostion.col);
1488             if (redrawSize.Width == 0.0)
1489                 redrawSize.Width = this.View.CaretWidthOnInsertMode;
1490             redrawSize.Height = layout.Height;
1491
1492             bool updateAll = this.View.LayoutLines.HilightAll() || this.View.LayoutLines.GenerateFolding();
1493
1494             if (updateAll)
1495                 this.Invalidate();
1496             else
1497                 this.Invalidate(new System.Drawing.Rectangle(this.View.CaretLocation, redrawSize));
1498         }
1499
1500         void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
1501         {
1502             this.SetSystemParamaters();
1503             this.Refresh();
1504         }
1505
1506         void SetSystemParamaters()
1507         {
1508             int CaretBlinkTime = SystemInformation.CaretBlinkTime;
1509             if (CaretBlinkTime == -1)
1510             {
1511                 this.View.CaretBlink = false;
1512                 if (this.IsHandleCreated)
1513                     this.BeginInvoke(new Action(() =>
1514                     {
1515                     this.Timer.Stop();
1516                     }));
1517             }
1518             else
1519             {
1520                 this.View.CaretBlink = true;
1521                 this.View.CaretBlinkTime = CaretBlinkTime * 2;
1522                 if(this.IsHandleCreated)
1523                     this.BeginInvoke(new Action(() =>
1524                     {
1525                         this.Timer.Start();
1526                     }));
1527             }
1528             this.View.CaretWidthOnInsertMode = SystemInformation.CaretWidth;
1529         }
1530
1531     }
1532
1533     /// <summary>
1534     /// FooEditEngineで使用するマウスイベント
1535     /// </summary>
1536     public class FooMouseEventArgs : MouseEventArgs
1537     {
1538         /// <summary>
1539         /// イベントが発生したインデックス
1540         /// </summary>
1541         public int index;
1542         /// <summary>
1543         /// 既定の処理を省略するなら真。そうでなければ偽
1544         /// </summary>
1545         public bool Handled;
1546         /// <summary>
1547         /// コンストラクター
1548         /// </summary>
1549         /// <param name="index">インデックス</param>
1550         /// <param name="button">押されているボタン</param>
1551         /// <param name="clicks">ボタンが押された回数</param>
1552         /// <param name="x">マウスカーソルがあるX座標</param>
1553         /// <param name="y">マウスカーソルがあるY座標</param>
1554         /// <param name="delta">ホイールの回転方向</param>
1555         public FooMouseEventArgs(int index, MouseButtons button, int clicks, int x, int y, int delta)
1556             : base(button, clicks, x, y, delta)
1557         {
1558             this.index = index;
1559         }
1560     }
1561
1562 }