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