OSDN Git Service

ファイル読み込み後の再描写はすぐ行わなくても構わない
[fooeditengine/FooEditEngine.git] / UWP / FooEditEngine.UWP / FooTextBox.cs
index 798875c..71da92f 100644 (file)
@@ -55,9 +55,13 @@ namespace FooEditEngine.UWP
 #endif
         bool nowCaretMove = false;
         bool nowCompstion = false;
+        bool requestSizeChange = false;
         Document _Document;
         DispatcherTimer timer = new DispatcherTimer();
 
+        const int Interval = 32;
+        const int IntervalWhenLostFocus = 160;
+
         /// <summary>
         /// コンストラクター
         /// </summary>
@@ -75,7 +79,7 @@ namespace FooEditEngine.UWP
 
             this.Document = new Document();
 
-            this.View = new EditView(this.Document, this.Render, new Padding(5, Gripper.HitAreaWidth, Gripper.HitAreaWidth / 2, Gripper.HitAreaWidth));
+            this.View = new EditView(this.Document, this.Render, new Padding(5, 5, Gripper.HitAreaWidth / 2, Gripper.HitAreaWidth));
             this.View.SrcChanged += View_SrcChanged;
             this.View.InsertMode = this.InsertMode;
             this.Document.DrawLineNumber = this.DrawLineNumber;
@@ -104,10 +108,13 @@ namespace FooEditEngine.UWP
             this.gestureRecongnizer.ManipulationUpdated += gestureRecongnizer_ManipulationUpdated;
             this.gestureRecongnizer.ManipulationCompleted += gestureRecongnizer_ManipulationCompleted;
 
-            this.timer.Interval = new TimeSpan(0, 0, 0, 0, 16);
+            this.timer.Interval = new TimeSpan(0, 0, 0, 0, Interval);
             this.timer.Tick += this.timer_Tick;
             this.timer.Start();
 
+            this.GettingFocus += FooTextBox_GettingFocus;
+            this.LosingFocus += FooTextBox_LosingFocus;
+
             this.SizeChanged += FooTextBox_SizeChanged;
 
             this.Loaded += FooTextBox_Loaded;
@@ -214,7 +221,13 @@ namespace FooEditEngine.UWP
             var dataPackageView = Clipboard.GetContent();
             if (dataPackageView.Contains(StandardDataFormats.Text))
             {
-                this._Controller.SelectedText = await dataPackageView.GetTextAsync();
+                try
+                {
+                    this._Controller.SelectedText = await dataPackageView.GetTextAsync();
+                }catch(Exception e)
+                {
+                    System.Diagnostics.Debug.WriteLine("past error:" + e.Message);
+                }
             }
         }
 
@@ -301,9 +314,12 @@ namespace FooEditEngine.UWP
         /// <summary>
         /// 再描写する
         /// </summary>
-        public void Refresh()
+        public void Refresh(bool immidately=true)
         {
-            this.Document.RequestRedraw();
+            if(immidately)
+                this.Refresh(this.View.PageBound);
+            else
+                this.Document.RequestRedraw();
         }
 
         /// <summary>
@@ -352,7 +368,7 @@ namespace FooEditEngine.UWP
                 if (this.verticalScrollBar != null)
                     this.verticalScrollBar.Maximum = this.View.LayoutLines.Count;
                 this.IsEnabled = true;
-                this.Refresh(this.View.PageBound);
+                this.Refresh(false);
             }
         }
 
@@ -428,12 +444,23 @@ namespace FooEditEngine.UWP
             }
         }
 
-            /// <inheritdoc/>
-        protected override async void OnGotFocus(RoutedEventArgs e)
+        private void FooTextBox_LosingFocus(UIElement sender, LosingFocusEventArgs args)
         {
-            base.OnGotFocus(e);
+            this.RemoveTextContext();
+            
+            if (this.textServiceManager != null)
+            {
+                this.textServiceManager.InputLanguageChanged -= TextServiceManager_InputLanguageChanged;
+                this.textServiceManager = null;
+            }
 
-            if(this.textServiceManager == null)
+            System.Diagnostics.Debug.WriteLine("losing focus");
+        }
+
+        private async void FooTextBox_GettingFocus(UIElement sender, GettingFocusEventArgs args)
+        {
+            System.Diagnostics.Debug.WriteLine("getting focus");
+            if (this.textServiceManager == null)
             {
                 await Task.Delay(500);
                 this.textServiceManager = CoreTextServicesManager.GetForCurrentView();
@@ -441,29 +468,35 @@ namespace FooEditEngine.UWP
             }
 
             this.CreateTextContext();
+        }
+
+        /// <inheritdoc/>
+        protected override void OnGotFocus(RoutedEventArgs e)
+        {
+            base.OnGotFocus(e);
+
+            System.Diagnostics.Debug.WriteLine("got focus");
 
             this.View.IsFocused = true;
-            this.timer.Start();
-            this.Refresh();
+            this.timer.Interval = new TimeSpan(0, 0, 0, 0, Interval);
+            this.Refresh(false);
         }
 
         private void TextServiceManager_InputLanguageChanged(CoreTextServicesManager sender, object args)
         {
             System.Diagnostics.Debug.WriteLine("input language changed input script:"+  this.textServiceManager.InputLanguage.Script);
-            this.RemoveTextContext();
-            this.CreateTextContext();
         }
 
-        /// <inheritdoc/>
+       /// <inheritdoc/>
         protected override void OnLostFocus(RoutedEventArgs e)
         {
             base.OnLostFocus(e);
 
-            this.RemoveTextContext();
-
+            System.Diagnostics.Debug.WriteLine("lost focus");
+            
             this.View.IsFocused = false;
-            this.Refresh(this.View.PageBound);
-            this.timer.Stop();
+            this.Refresh(false);
+            this.timer.Interval = new TimeSpan(0, 0, 0, 0, IntervalWhenLostFocus);
         }
 
         private void CreateTextContext()
@@ -471,6 +504,7 @@ namespace FooEditEngine.UWP
             if(this.textServiceManager != null)
             {
                 this.textEditContext = this.textServiceManager.CreateEditContext();
+                this.textEditContext.InputScope = CoreTextInputScope.Text;
                 this.textEditContext.CompositionStarted += TextEditContext_CompositionStarted;
                 this.textEditContext.CompositionCompleted += TextEditContext_CompositionCompleted;
                 this.textEditContext.LayoutRequested += TextEditContext_LayoutRequested;
@@ -489,6 +523,7 @@ namespace FooEditEngine.UWP
         {
             if(this.textEditContext != null)
             {
+                this.textEditContext.NotifyFocusLeave();
                 this.textEditContext.CompositionStarted -= TextEditContext_CompositionStarted;
                 this.textEditContext.CompositionCompleted -= TextEditContext_CompositionCompleted;
                 this.textEditContext.LayoutRequested -= TextEditContext_LayoutRequested;
@@ -499,7 +534,6 @@ namespace FooEditEngine.UWP
                 this.textEditContext.FormatUpdating -= TextEditContext_FormatUpdating;
                 this.textEditContext.FocusRemoved -= TextEditContext_FocusRemoved;
                 this.textEditContext.NotifyFocusLeaveCompleted -= TextEditContext_NotifyFocusLeaveCompleted;
-                this.textEditContext.NotifyFocusLeave();
                 this.textEditContext = null;
             }
         }
@@ -670,6 +704,7 @@ namespace FooEditEngine.UWP
         /// <inheritdoc/>
         protected override void OnPointerPressed(PointerRoutedEventArgs e)
         {
+            System.Diagnostics.Debug.WriteLine("pointer pressed");
             this.CapturePointer(e.Pointer);
             this.gestureRecongnizer.ProcessDownEvent(e.GetCurrentPoint(this));
             e.Handled = true;
@@ -678,7 +713,15 @@ namespace FooEditEngine.UWP
         /// <inheritdoc/>
         protected override void OnPointerMoved(PointerRoutedEventArgs e)
         {
-            this.gestureRecongnizer.ProcessMoveEvents(e.GetIntermediatePoints(this));
+            System.Diagnostics.Debug.WriteLine("pointer moved");
+            try
+            {
+                this.gestureRecongnizer.ProcessMoveEvents(e.GetIntermediatePoints(this));
+            }catch(System.Runtime.InteropServices.COMException ex)
+            {
+                //ピンチズームでこの例外が発生するが、回避できない
+                System.Diagnostics.Debug.WriteLine("expection:" + ex);
+            }
             e.Handled = true;
 
             if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
@@ -702,6 +745,7 @@ namespace FooEditEngine.UWP
         /// <inheritdoc/>
         protected override void OnPointerReleased(PointerRoutedEventArgs e)
         {
+            System.Diagnostics.Debug.WriteLine("pointer released");
             this.gestureRecongnizer.ProcessUpEvent(e.GetCurrentPoint(this));
             e.Handled = true;
         }
@@ -709,6 +753,7 @@ namespace FooEditEngine.UWP
         /// <inheritdoc/>
         protected override void OnPointerCanceled(PointerRoutedEventArgs e)
         {
+            System.Diagnostics.Debug.WriteLine("pointer canceled");
             this.gestureRecongnizer.CompleteGesture();
             e.Handled = true;
         }
@@ -716,6 +761,7 @@ namespace FooEditEngine.UWP
         /// <inheritdoc/>
         protected override void OnPointerWheelChanged(PointerRoutedEventArgs e)
         {
+            System.Diagnostics.Debug.WriteLine("pointer wheelchanged");
             bool shift = (e.KeyModifiers & Windows.System.VirtualKeyModifiers.Shift) ==
                 Windows.System.VirtualKeyModifiers.Shift;
             bool ctrl = (e.KeyModifiers & Windows.System.VirtualKeyModifiers.Control) ==
@@ -826,7 +872,7 @@ namespace FooEditEngine.UWP
                 args.Request.LayoutBounds.TextBounds = new Rect(
                     screenStartPos.X,
                     screenStartPos.Y,
-                    screenEndPos.X - screenStartPos.X,
+                    Math.Max(0,screenEndPos.X - screenStartPos.X),  //折り返されている場合、負になることがある
                     screenEndPos.Y - screenStartPos.Y);
             }
 
@@ -1062,22 +1108,36 @@ namespace FooEditEngine.UWP
                             this._Controller.RectSelection = true;
                         }));
                     }
-                    await ContextMenu.ShowAsync(e.Position);
+                    var windowStartPos = Util.GetPointInWindow(e.Position, this);
+                    await ContextMenu.ShowAsync(windowStartPos);
                 }
             }
         }
 
+        long lastDouleTapTick;
+        const long allowTripleTapTimeSpan = 500;
         void gestureRecongnizer_Tapped(GestureRecognizer sender, TappedEventArgs e)
         {
             bool touched = e.PointerDeviceType == PointerDeviceType.Touch;
             this.Document.SelectGrippers.BottomLeft.Enabled = false;
             this.Document.SelectGrippers.BottomRight.Enabled = touched;
             this.JumpCaret(e.Position);
-            if (e.TapCount == 2)
+            if(e.TapCount == 1 && System.DateTime.Now.Ticks - lastDouleTapTick < allowTripleTapTimeSpan * 10000)    //トリプルタップ
             {
+                //タッチスクリーンで行選択した場合、アンカーインデックスを単語の先頭にしないとバグる
                 this.Document.SelectGrippers.BottomLeft.Enabled = touched;
-                //タッチスクリーンでダブルタップした場合、アンカーインデックスを単語の先頭にしないとバグる
-                this.Document.SelectWord(this.Controller.SelectionStart, touched);
+                this.Document.SelectLine(this.Controller.SelectionStart, touched);
+                this.Refresh();
+            }
+            else  if(e.TapCount == 2)   //ダブルタップ
+            {
+                //タッチスクリーンで単語選択した場合、アンカーインデックスを単語の先頭にしないとバグる
+                this.Document.SelectGrippers.BottomLeft.Enabled = touched;
+                if (e.Position.X < this.Render.TextArea.X)
+                    this.Document.SelectLine(this.Controller.SelectionStart, touched);
+                else
+                    this.Document.SelectWord(this.Controller.SelectionStart, touched);
+                this.lastDouleTapTick = System.DateTime.Now.Ticks;
                 this.Refresh();
             }
         }
@@ -1123,7 +1183,7 @@ namespace FooEditEngine.UWP
             else
                 return;
             TextPoint tp = this.View.GetTextPointFromPostion(p, searchRange);
-            this._Controller.MoveCaretAndSelect(tp);
+            this._Controller.MoveCaretAndSelect(tp, this.IsModiferKeyPressed(VirtualKey.LeftControl));
 #if ENABLE_AUTMATION
             if (this.peer != null)
                 this.peer.OnNotifyCaretChanged();
@@ -1188,11 +1248,8 @@ namespace FooEditEngine.UWP
 
         void FooTextBox_SizeChanged(object sender, SizeChangedEventArgs e)
         {
-            if (this.Resize(this.rectangle.ActualWidth, this.rectangle.ActualHeight))
-            {
-                this.Refresh();
-                return;
-            }
+            //LostFocusやGotFocusなどと競合するとDirect2Dでエラーが起きるので、timer_tickイベントでサイズ変更を行うことにした
+            this.requestSizeChange = true;
         }
 
         void horizontalScrollBar_Scroll(object sender, ScrollEventArgs e)
@@ -1261,10 +1318,21 @@ namespace FooEditEngine.UWP
 
         void timer_Tick(object sender, object e)
         {
-            if (this.View.LayoutLines.HilightAll() || this.View.LayoutLines.GenerateFolding() || this.Document.IsRequestRedraw)
+            this.timer.Stop();
+            if(this.requestSizeChange)
+            {
+                if (this.Resize(this.rectangle.ActualWidth, this.rectangle.ActualHeight))
+                {
+                    //普通に再描写するとちらつく
+                    this.Refresh(this.View.PageBound);
+                }
+                this.requestSizeChange = false;
+            }
+            else if (this.View.LayoutLines.HilightAll() || this.View.LayoutLines.GenerateFolding() || this.Document.IsRequestRedraw)
             {
                 this.Refresh(this.View.PageBound);
             }
+            this.timer.Start();
         }
 
         private void SetDocument(Document value)
@@ -1279,6 +1347,7 @@ namespace FooEditEngine.UWP
                 old_doc.Update -= new DocumentUpdateEventHandler(Document_Update);
                 this._Document.SelectionChanged -= Controller_SelectionChanged;
                 this._Document.LoadProgress -= Document_LoadProgress;
+                this._Document.AutoCompleteChanged -= _Document_AutoCompleteChanged;
                 if (this._Document.AutoComplete != null)
                 {
                     this._Document.AutoComplete.GetPostion = null;
@@ -1295,22 +1364,9 @@ namespace FooEditEngine.UWP
             this._Document.LayoutLines.Render = this.Render;
             this._Document.Update += new DocumentUpdateEventHandler(Document_Update);
             this._Document.LoadProgress += Document_LoadProgress;
-            if(this._Document.AutoComplete != null)
-            {
-                this._Document.AutoComplete.GetPostion = (tp,doc) =>
-                {
-                    var p = this.View.GetPostionFromTextPoint(tp);
-                    int height = (int)doc.LayoutLines.GetLayout(doc.CaretPostion.row).Height;
-
-                    if (p.Y + AutoCompleteBox.CompleteListBoxHeight + height > doc.LayoutLines.Render.TextArea.Height)
-                        p.Y -= AutoCompleteBox.CompleteListBoxHeight;
-                    else
-                        p.Y += height;
-                    //AutoCompleteBox内ではCanvasで位置を指定しているので変換する必要がある
-                    var pointInWindow = Util.GetPointInWindow(p, this);
-                  return pointInWindow;
-                };
-            }
+            this._Document.AutoCompleteChanged += _Document_AutoCompleteChanged;
+            if (this._Document.AutoComplete != null && this._Document.AutoComplete.GetPostion == null)
+                this._Document_AutoCompleteChanged(this._Document, null);
             //初期化が終わっていればすべて存在する
             if (this.Controller != null && this.View != null)
             {
@@ -1343,6 +1399,24 @@ namespace FooEditEngine.UWP
             this._Document.SelectionChanged += Controller_SelectionChanged;
         }
 
+        private void _Document_AutoCompleteChanged(object sender, EventArgs e)
+        {
+            Document doc = (Document)sender;
+            doc.AutoComplete.GetPostion = (tp, e_doc) =>
+            {
+                var p = this.View.GetPostionFromTextPoint(tp);
+                int height = (int)e_doc.LayoutLines.GetLayout(e_doc.CaretPostion.row).Height;
+
+                if (p.Y + AutoCompleteBox.CompleteListBoxHeight + height > e_doc.LayoutLines.Render.TextArea.Height)
+                    p.Y -= AutoCompleteBox.CompleteListBoxHeight;
+                else
+                    p.Y += height;
+                //AutoCompleteBox内ではCanvasで位置を指定しているので変換する必要がある
+                var pointInWindow = Util.GetPointInWindow(p, this);
+                return pointInWindow;
+            };
+        }
+
         /// <inheritdoc/>
         public static void OnPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
         {
@@ -1405,6 +1479,8 @@ namespace FooEditEngine.UWP
                 source.Render.FontSize = source.FontSize;
             if (e.Property.Equals(ForegroundProperty))
                 source.Render.Foreground = D2DRenderBase.ToColor4(source.Foreground);
+            if (e.Property.Equals(HilightForegroundProperty))
+                source.Render.HilightForeground = D2DRenderBase.ToColor4(source.HilightForeground);
             if (e.Property.Equals(BackgroundProperty))
                 source.Render.Background = D2DRenderBase.ToColor4(source.Background);
             if (e.Property.Equals(ControlCharProperty))
@@ -1711,6 +1787,21 @@ namespace FooEditEngine.UWP
             DependencyProperty.Register("Foreground", typeof(Windows.UI.Color), typeof(FooTextBox), new PropertyMetadata(Colors.Black, OnPropertyChanged));
 
         /// <summary>
+        /// 選択時の文字色を表す。これは依存プロパティです
+        /// </summary>
+        public Windows.UI.Color HilightForeground
+        {
+            get { return (Windows.UI.Color)GetValue(HilightForegroundProperty); }
+            set { SetValue(HilightForegroundProperty, value); }
+        }
+
+        /// <summary>
+        /// HilightForegroundForegroundの依存プロパティを表す
+        /// </summary>
+        public static readonly DependencyProperty HilightForegroundProperty =
+            DependencyProperty.Register("HilightForeground", typeof(Windows.UI.Color), typeof(FooTextBox), new PropertyMetadata(Colors.White, OnPropertyChanged));
+
+        /// <summary>
         /// 背景色を表す。これは依存プロパティです
         /// </summary>
         public new Windows.UI.Color Background
@@ -1753,7 +1844,7 @@ namespace FooEditEngine.UWP
         /// Hilightの依存プロパティを表す
         /// </summary>
         public static readonly DependencyProperty HilightProperty =
-            DependencyProperty.Register("Hilight", typeof(Windows.UI.Color), typeof(FooTextBox), new PropertyMetadata(Colors.DeepSkyBlue, OnPropertyChanged));
+            DependencyProperty.Register("Hilight", typeof(Windows.UI.Color), typeof(FooTextBox), new PropertyMetadata(Colors.DodgerBlue, OnPropertyChanged));
 
         /// <summary>
         /// キーワード1の文字色を表す。これは依存プロパティです