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             this.Brushes.RenderChanged += Brushes_RenderChanged;
37         }
38
39         public bool ContainsSymbol(char c)
40         {
41             if (c == '\t' && (this.InlineTabs == null || this.InlineTabs.Count > 0))
42                 return true;
43             return this.InlineChars.ContainsKey(c);
44         }
45
46         public void AddSymbol(char c, char alt)
47         {
48             if (c == '\t')
49             {
50                 this.InlineTabs = new MultiSet<double,InlineTab>();
51             }
52             else
53             {
54                 D2D.SolidColorBrush brush = this.Brushes.Get(this.Fore);
55                 for (int i = 0; i < DuplicateCount; i++)
56                 {
57                     this.InlineChars.Add(c, new InlineChar(this.Factory, this.Format, brush, alt));
58                 }
59             }
60         }
61
62         public void RemoveSymbol(char c)
63         {
64             if (c == '\t')
65                 this.InlineTabs = null;
66             else
67                 this.InlineChars.Remove(c);
68         }
69
70         public Color4 Fore
71         {
72             get
73             {
74                 return this._Fore;
75             }
76             set
77             {
78                 this._Fore = value;
79                 this.Format = this._Format;
80             }
81         }
82
83         public DW.TextFormat Format
84         {
85             get
86             {
87                 return this._Format;
88             }
89             set
90             {
91                 this._Format = value;
92
93                 this.TabWidth = this._TabWidth;
94
95                 this.ReGenerate();
96             }
97         }
98
99         public double TabWidth
100         {
101             get
102             {
103                 return this._TabWidth;
104             }
105             set
106             {
107                 this._TabWidth = value; 
108                 if(this.InlineTabs != null)
109                     this.InlineTabs.Clear();
110             }
111         }
112
113         public DW.InlineObject Get(MyTextLayout layout,int index, string str)
114         {
115             if (str[index] == '\t')
116             {
117                 if (this.InlineTabs == null)
118                     return null;
119                 double x = layout.GetColPostionFromIndex(index);
120                 if (layout.RightToLeft)
121                     x = layout.MaxWidth - x;
122                 double width;
123                 if (index > 0 && str[index - 1] == '\t')
124                     width = this._TabWidth;
125                 else
126                     width = this._TabWidth - x % this._TabWidth;
127                 List<InlineTab> collection;
128                 if (!this.InlineTabs.TryGet(width, out collection))
129                 {
130                     collection = new List<InlineTab>();
131                     D2D.SolidColorBrush brush = this.Brushes.Get(this.Fore);
132                     for (int i = 0; i < DuplicateCount; i++)
133                         collection.Add(new InlineTab(brush, width,layout.Height));
134                     this.InlineTabs.Add(width, collection);
135                 }
136                 return collection[index % DuplicateCount];
137             }
138             else
139             {
140                 char c = str[index];
141                 if (this.InlineChars.ContainsKey(c) == false)
142                     return null;
143                 return this.InlineChars.Get(c, index % DuplicateCount);
144             }
145         }
146
147         public void Clear()
148         {
149             if(this.InlineChars != null)
150                 this.InlineChars.Clear();
151             if(this.InlineTabs != null)
152                 this.InlineTabs.Clear();
153         }
154
155         void ReGenerate()
156         {
157             List<KeyValuePair<char, char>> list = new List<KeyValuePair<char, char>>(this.InlineChars.Count);
158             foreach (KeyValuePair<char, InlineChar> kv in this.InlineChars.EnumrateKeyAndFirstValue())
159                 list.Add(new KeyValuePair<char, char>(kv.Key, kv.Value.AlternativeChar));
160
161             this.InlineChars.Clear();
162
163             if (this.InlineTabs == null)
164                 return;
165
166             this.InlineTabs.Clear();
167
168             D2D.SolidColorBrush brush = this.Brushes.Get(this.Fore);
169             foreach (KeyValuePair<char, char> kv in list)
170                 for (int i = 0; i < DuplicateCount; i++)
171                     this.InlineChars.Add(kv.Key, new InlineChar(this.Factory, this.Format, brush, kv.Value));
172         }
173
174         void Brushes_RenderChanged(object sender, EventArgs e)
175         {
176             this.ReGenerate();
177         }
178     }
179     sealed class MultiSet<T, J>
180         where J : IDisposable
181     {
182         Dictionary<T, List<J>> Collection = new Dictionary<T, List<J>>();
183
184         public void Add(T key, List<J> collection)
185         {
186             if (this.Collection.ContainsKey(key) == false)
187                 this.Collection.Add(key, collection);
188         }
189
190         public void Add(T key, J value)
191         {
192             if (this.Collection.ContainsKey(key) == false)
193                 this.Collection.Add(key, new List<J>());
194             this.Collection[key].Add(value);
195         }
196
197         public int Count
198         {
199             get
200             {
201                 return this.Collection.Count;
202             }
203         }
204
205         public bool ContainsKey(T key)
206         {
207             return this.Collection.ContainsKey(key);
208         }
209
210         public bool TryGet(T key, out List<J> value)
211         {
212             return this.Collection.TryGetValue(key, out value);
213         }
214
215         public J Get(T key,int index)
216         {
217             return this.Collection[key][index];
218         }
219
220         public void Remove(T key)
221         {
222             if (this.Collection.ContainsKey(key) == false)
223                 return;
224             foreach (J value in this.Collection[key])
225                 value.Dispose();
226             this.Collection.Remove(key);
227         }
228
229         public void Clear()
230         {
231             foreach (List<J> list in this.Collection.Values)
232                 foreach (J value in list)
233                     value.Dispose();
234             this.Collection.Clear();
235         }
236
237         public IEnumerable<KeyValuePair<T, J>> EnumrateKeyAndFirstValue()
238         {
239             foreach (KeyValuePair<T, List<J>> kv in this.Collection)
240                 yield return new KeyValuePair<T, J>(kv.Key, kv.Value[0]);
241         }
242     }
243 }