OSDN Git Service

WPF版にも自動補完機能を追加した
authorkonekoneko <test2214@hotmail.co.jp>
Sun, 13 Nov 2016 09:06:21 +0000 (14:36 +0530)
committerkonekoneko <test2214@hotmail.co.jp>
Sun, 13 Nov 2016 09:06:21 +0000 (14:36 +0530)
Core/Util.cs
WPF/FooEditEngine/AutoCompleteBox.cs [new file with mode: 0644]
WPF/FooEditEngine/FooEditEngine.csproj
WPF/FooEditEngine/FooTextBox.cs
WPF/Test/MainWindow.xaml.cs

index 255de09..0180a78 100644 (file)
@@ -91,6 +91,22 @@ namespace FooEditEngine
             return chars;
         }
 #else
+        public static void GetDpi(out float dpix, out float dpiy)
+        {
+            var dpiXProperty = typeof(System.Windows.SystemParameters).GetProperty("DpiX", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+            var dpiYProperty = typeof(System.Windows.SystemParameters).GetProperty("Dpi", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+
+            dpix = (int)dpiXProperty.GetValue(null, null);
+            dpiy = (int)dpiYProperty.GetValue(null, null);
+        }
+
+        public static double GetScale()
+        {
+            float dpi;
+            Util.GetDpi(out dpi, out dpi);
+            return dpi / 96.0;
+        }
+
         public static IEnumerable<char> GetEnumrator(string s)
         {
             return s;
diff --git a/WPF/FooEditEngine/AutoCompleteBox.cs b/WPF/FooEditEngine/AutoCompleteBox.cs
new file mode 100644 (file)
index 0000000..d3911de
--- /dev/null
@@ -0,0 +1,169 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+using FooEditEngine;
+
+namespace FooEditEngine.WPF
+{
+    /// <summary>
+    /// 自動補完用クラス
+    /// </summary>
+    public class AutoCompleteBox : AutoCompleteBoxBase
+    {
+        private string inputedWord;
+        private ListBox listBox1 = new ListBox();
+        private Popup popup;
+        private Document doc;
+
+        /// <summary>
+        /// コンストラクター
+        /// </summary>
+        /// <param name="doc">ドキュメント</param>
+        public AutoCompleteBox(Document doc) : base(doc)
+        {
+            //リストボックスを追加する
+            this.listBox1.MouseDoubleClick += listBox1_MouseDoubleClick;
+            this.listBox1.KeyDown += listBox1_KeyDown;
+            this.listBox1.Height = 200;
+            this.doc = doc;
+        }
+
+        /// <summary>
+        /// オートコンプリートの対象となる単語のリスト
+        /// </summary>
+        public override CompleteCollection<ICompleteItem> Items
+        {
+            get
+            {
+                return (CompleteCollection<ICompleteItem>)this.listBox1.ItemsSource;
+            }
+            set
+            {
+                this.listBox1.ItemsSource = value;
+                this.listBox1.DisplayMemberPath = CompleteCollection<ICompleteItem>.ShowMember;
+            }
+        }
+
+        /// <summary>
+        /// 自動補完リストが表示されているかどうか
+        /// </summary>
+        public override bool IsCloseCompleteBox
+        {
+            get
+            {
+                return !this.popup.IsOpen;
+            }
+        }
+
+        internal Popup TargetPopup
+        {
+            get
+            {
+                return this.popup;
+            }
+            set
+            {
+                this.popup = value;
+                this.popup.Child = this.listBox1;
+                this.popup.Height = 200;
+            }
+        }
+
+        /// <summary>
+        /// 補完候補の表示要求を処理する
+        /// </summary>
+        /// <param name="ev"></param>
+        protected override void RequestShowCompleteBox(ShowingCompleteBoxEventArgs ev)
+        {
+            this.inputedWord = ev.inputedWord;
+            DecideListBoxLocation(this.doc,this.listBox1, ev.CaretPostion);
+            this.listBox1.SelectedIndex = ev.foundIndex;
+            this.listBox1.ScrollIntoView(this.listBox1.SelectedItem);
+            this.popup.IsOpen = true;
+        }
+
+        /// <summary>
+        /// 補完候補の非表示要求を処理する
+        /// </summary>
+        protected override void RequestCloseCompleteBox()
+        {
+            this.popup.IsOpen = false;
+        }
+
+        void DecideListBoxLocation(Document doc, ListBox listbox, Point p)
+        {
+            this.popup.PlacementRectangle = new Rect(p, new Size(listBox1.ActualWidth, listBox1.Height));
+        }
+
+        internal bool ProcessKeyDown(FooTextBox textbox, KeyEventArgs e,bool isCtrl,bool isShift)
+        {
+            if (this.popup.IsOpen == false)
+            {
+                if (e.Key == Key.Space && isCtrl)
+                {
+                    this.OpenCompleteBox(string.Empty);
+                    e.Handled = true;
+
+                    return true;
+                }
+                return false;
+            }
+
+            switch (e.Key)
+            {
+                case Key.Escape:
+                    this.RequestCloseCompleteBox();
+                    textbox.Focus();
+                    e.Handled = true;
+                    return true;
+                case Key.Down:
+                    if (this.listBox1.SelectedIndex + 1 >= this.listBox1.Items.Count)
+                        this.listBox1.SelectedIndex = this.listBox1.Items.Count - 1;
+                    else
+                        this.listBox1.SelectedIndex++;
+                    this.listBox1.ScrollIntoView(this.listBox1.SelectedItem);
+                    e.Handled = true;
+                    return true;
+                case Key.Up:
+                    if (this.listBox1.SelectedIndex - 1 < 0)
+                        this.listBox1.SelectedIndex = 0;
+                    else
+                        this.listBox1.SelectedIndex--;
+                    this.listBox1.ScrollIntoView(this.listBox1.SelectedItem);
+                    e.Handled = true;
+                    return true;
+                case Key.Enter:
+                    this.RequestCloseCompleteBox();
+                    CompleteWord selWord = (CompleteWord)this.listBox1.SelectedItem;
+                    this.SelectItem(this, new SelectItemEventArgs(selWord.word, this.inputedWord, this.Document));
+                    e.Handled = true;
+                    return true;
+            }
+
+            return false;
+        }
+
+        private void listBox1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+        {
+            this.popup.IsOpen = false;
+            CompleteWord selWord = (CompleteWord)this.listBox1.SelectedItem;
+            this.SelectItem(this, new SelectItemEventArgs(selWord.word, this.inputedWord, this.Document));
+        }
+
+        void listBox1_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.Key == Key.Enter)
+            {
+                this.popup.IsOpen = false;
+                CompleteWord selWord = (CompleteWord)this.listBox1.SelectedItem;
+                this.SelectItem(this, new SelectItemEventArgs(selWord.word, this.inputedWord, this.Document));
+                e.Handled = true;
+            }
+        }
+    }
+}
index 7755952..0026532 100644 (file)
@@ -78,6 +78,7 @@
     </Page>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="AutoCompleteBox.cs" />
     <Compile Include="Direct2D\D2DRender.cs" />
     <Compile Include="Direct2D\NativeMethods.cs" />
     <Compile Include="FooPrintText.cs" />
index 133bbbd..073e071 100644 (file)
@@ -46,6 +46,7 @@ namespace FooEditEngine.WPF
         FooTextBoxAutomationPeer peer;
         bool isNotifyChanged = false;
         Document _Document;
+        Popup popup;
         
         static FooTextBox()
         {
@@ -59,6 +60,8 @@ namespace FooEditEngine.WPF
         /// </summary>
         public FooTextBox()
         {
+            this.popup = new Popup();
+
             this.image = new Image();
             this.image.Stretch = Stretch.Fill;
             this.image.HorizontalAlignment = HorizontalAlignment.Left;
@@ -166,6 +169,12 @@ namespace FooEditEngine.WPF
                 Grid.SetRow(this.image, 0);
                 Grid.SetColumn(this.image, 0);
                 grid.Children.Add(this.image);
+
+                Grid.SetRow(this.popup, 0);
+                Grid.SetColumn(this.popup, 0);
+                grid.Children.Add(this.popup);
+                //this.popup.PlacementTarget = this;
+                this.popup.Placement = PlacementMode.Absolute;
             }
 
             this.horizontalScrollBar = this.GetTemplateChild("PART_HorizontalScrollBar") as ScrollBar;
@@ -706,6 +715,15 @@ namespace FooEditEngine.WPF
                 return;
 
             ModifierKeys modiferKeys = e.KeyboardDevice.Modifiers;
+
+            var autocomplete = this.Document.AutoComplete as AutoCompleteBox;
+            if (autocomplete != null &&
+                autocomplete.ProcessKeyDown(this,e, this.IsPressedModifierKey(modiferKeys, ModifierKeys.Control), this.IsPressedModifierKey(modiferKeys, ModifierKeys.Shift)))
+            {
+                e.Handled = true;
+                return;
+            }
+
             bool movedCaret = false;
             switch (e.Key)
             {
@@ -1225,12 +1243,29 @@ namespace FooEditEngine.WPF
                 old_doc.LoadProgress -= Document_LoadProgress;
                 old_doc.SelectionChanged += new EventHandler(Controller_SelectionChanged);
                 oldLength = old_doc.Length;
+                if (this._Document.AutoComplete != null)
+                {
+                    ((AutoCompleteBox)this._Document.AutoComplete).TargetPopup = null;
+                    this._Document.AutoComplete.GetPostion = null;
+                    this._Document.AutoComplete = null;
+                }
             }
 
             this._Document = value;
             this._Document.LayoutLines.Render = this.Render;
             this._Document.Update += new DocumentUpdateEventHandler(Document_Update);
             this._Document.LoadProgress += Document_LoadProgress;
+            if (this._Document.AutoComplete != null)
+            {
+                ((AutoCompleteBox)this._Document.AutoComplete).TargetPopup = this.popup;
+                this._Document.AutoComplete.GetPostion = (tp) =>
+                {
+                    var p = this.View.GetPostionFromTextPoint(tp);
+                    int height = (int)this._Document.LayoutLines.GetLayout(this._Document.CaretPostion.row).Height;
+                    p.Y += height;
+                    return PointToScreen(this.TranslatePoint(p.Scale(Util.GetScale()), this));
+                };
+            }
             //初期化が終わっていればすべて存在する
             if (this.Controller != null && this.View != null && this.textStore != null)
             {
index 601299a..bf6ee18 100644 (file)
@@ -41,7 +41,21 @@ namespace Test
             this.fooTextBox.FoldingStrategy = new CharFoldingMethod('{', '}');
             this.fooTextBox.Document.Update += Document_Update;
 
-            this.Documents.Add(this.fooTextBox.Document);
+            var complete_collection = new CompleteCollection<ICompleteItem>();
+            complete_collection.Add(new CompleteWord("int"));
+            complete_collection.Add(new CompleteWord("float"));
+            complete_collection.Add(new CompleteWord("double"));
+            complete_collection.Add(new CompleteWord("byte"));
+            complete_collection.Add(new CompleteWord("char"));
+            complete_collection.Add(new CompleteWord("var"));
+
+            Document doc = new Document();
+            doc.AutoComplete = new AutoCompleteBox(doc);
+            doc.AutoComplete.Items = complete_collection;
+
+            this.fooTextBox.Document = doc;
+
+            this.Documents.Add(doc);
             this.Documents.Add(new Document());
 
             this.Closed += MainWindow_Closed;