OSDN Git Service

タブの表示を無効にするとほかの文字列まで表示されないバグを修正した
[fooeditengine/FooEditEngine.git] / Core / Direct2D / MultiSet.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.Collections.Generic;
13 using SharpDX;
14 using D2D = SharpDX.Direct2D1;
15 using DW = SharpDX.DirectWrite;
16
17 namespace FooEditEngine
18 {
19     sealed class InlineManager
20     {
21         DW.Factory Factory;
22         DW.TextFormat _Format;
23         Color4 _Fore;
24         MultiSet<char, InlineChar> InlineChars = new MultiSet<char, InlineChar>();
25         MultiSet<double, InlineTab> InlineTabs = null;
26         ColorBrushCollection Brushes;
27         double _TabWidth;
28         const int DuplicateCount = 2;   //1だとDirectWriteが一つにまとめてしまう
29
30         public InlineManager(DW.Factory factory, DW.TextFormat format, Color4 fore, ColorBrushCollection brushes)
31         {
32             this.Factory = factory;
33             this._Format = format;
34             this._Fore = fore;
35             this.Brushes = brushes;
36         }
37
38         public bool ContainsSymbol(char c)
39         {
40             if (c == '\t')
41                 return this.InlineTabs != null && this.InlineTabs.Count > 0;
42             return this.InlineChars.ContainsKey(c);
43         }
44
45         public void AddSymbol(char c, char alt)
46         {
47             if (c == '\t')
48             {
49                 this.InlineTabs = new MultiSet<double, InlineTab>();
50             }
51             else
52             {
53                 for (int i = 0; i < DuplicateCount; i++)
54                 {
55                     this.InlineChars.Add(c, new InlineChar(this.Factory, this.Format, this.Brushes, this.Fore, alt));
56                 }
57             }
58         }
59
60         public void RemoveSymbol(char c)
61         {
62             if (c == '\t')
63                 this.InlineTabs = null;
64             else
65                 this.InlineChars.Remove(c);
66         }
67
68         public Color4 Fore
69         {
70             get
71             {
72                 return this._Fore;
73             }
74             set
75             {
76                 this._Fore = value;
77                 this.Format = this._Format;
78             }
79         }
80
81         public DW.TextFormat Format
82         {
83             get
84             {
85                 return this._Format;
86             }
87             set
88             {
89                 this._Format = value;
90
91                 this.TabWidth = this._TabWidth;
92
93                 this.ReGenerate();
94             }
95         }
96
97         public double TabWidth
98         {
99             get
100             {
101                 return this._TabWidth;
102             }
103             set
104             {
105                 this._TabWidth = value;
106                 if (this.InlineTabs != null)
107                     this.InlineTabs.Clear();
108             }
109         }
110
111         public DW.InlineObject Get(MyTextLayout layout, int index, string str)
112         {
113             if (str[index] == '\t')
114             {
115                 if (this.InlineTabs == null)
116                     return null;
117                 double x = layout.GetColPostionFromIndex(index);
118                 if (layout.RightToLeft)
119                     x = layout.MaxWidth - x;
120                 double width;
121                 if (index > 0 && str[index - 1] == '\t')
122                     width = this._TabWidth;
123                 else
124                     width = this._TabWidth - x % this._TabWidth;
125                 List<InlineTab> collection;
126                 if (!this.InlineTabs.TryGet(width, out collection))
127                 {
128                     collection = new List<InlineTab>();
129                     for (int i = 0; i < DuplicateCount; i++)
130                         collection.Add(new InlineTab(this.Brushes, this.Fore, width, layout.Height));
131                     this.InlineTabs.Add(width, collection);
132                 }
133                 return collection[index % DuplicateCount];
134             }
135             else
136             {
137                 char c = str[index];
138                 if (this.InlineChars.ContainsKey(c) == false)
139                     return null;
140                 return this.InlineChars.Get(c, index % DuplicateCount);
141             }
142         }
143
144         public void Clear()
145         {
146             if (this.InlineChars != null)
147                 this.InlineChars.Clear();
148             if (this.InlineTabs != null)
149                 this.InlineTabs.Clear();
150         }
151
152         public void ReGenerate()
153         {
154             List<KeyValuePair<char, char>> list = new List<KeyValuePair<char, char>>(this.InlineChars.Count);
155             foreach (KeyValuePair<char, InlineChar> kv in this.InlineChars.EnumrateKeyAndFirstValue())
156                 list.Add(new KeyValuePair<char, char>(kv.Key, kv.Value.AlternativeChar));
157
158             this.InlineChars.Clear();
159
160             if (this.InlineTabs != null)
161                 this.InlineTabs.Clear();
162
163             foreach (KeyValuePair<char, char> kv in list)
164                 for (int i = 0; i < DuplicateCount; i++)
165                     this.InlineChars.Add(kv.Key, new InlineChar(this.Factory, this.Format, this.Brushes, this.Fore, kv.Value));
166         }
167
168     }
169     sealed class MultiSet<T, J>
170         where J : IDisposable
171     {
172         Dictionary<T, List<J>> Collection = new Dictionary<T, List<J>>();
173
174         public void Add(T key, List<J> collection)
175         {
176             if (this.Collection.ContainsKey(key) == false)
177                 this.Collection.Add(key, collection);
178         }
179
180         public void Add(T key, J value)
181         {
182             if (this.Collection.ContainsKey(key) == false)
183                 this.Collection.Add(key, new List<J>());
184             this.Collection[key].Add(value);
185         }
186
187         public int Count
188         {
189             get
190             {
191                 return this.Collection.Count;
192             }
193         }
194
195         public bool ContainsKey(T key)
196         {
197             return this.Collection.ContainsKey(key);
198         }
199
200         public bool TryGet(T key, out List<J> value)
201         {
202             return this.Collection.TryGetValue(key, out value);
203         }
204
205         public J Get(T key, int index)
206         {
207             return this.Collection[key][index];
208         }
209
210         public void Remove(T key)
211         {
212             if (this.Collection.ContainsKey(key) == false)
213                 return;
214             foreach (J value in this.Collection[key])
215                 value.Dispose();
216             this.Collection.Remove(key);
217         }
218
219         public void Clear()
220         {
221             foreach (List<J> list in this.Collection.Values)
222                 foreach (J value in list)
223                     value.Dispose();
224             this.Collection.Clear();
225         }
226
227         public IEnumerable<KeyValuePair<T, J>> EnumrateKeyAndFirstValue()
228         {
229             foreach (KeyValuePair<T, List<J>> kv in this.Collection)
230                 yield return new KeyValuePair<T, J>(kv.Key, kv.Value[0]);
231         }
232     }
233 }