1 /**
2 * Glyph selector dialog.
3 */
5 /* Authors:
6 * Jon A. Cruz
7 *
8 * Copyright (C) 2010 Jon A. Cruz
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include <vector>
14 #include <glibmm/i18n.h>
15 #include <gtkmm/entry.h>
16 #include <gtkmm/iconview.h>
17 #include <gtkmm/label.h>
18 #include <gtkmm/liststore.h>
19 #include <gtkmm/scrolledwindow.h>
20 #include <gtkmm/table.h>
21 #include <gtkmm/treemodelcolumn.h>
22 #include <gtkmm/widget.h>
24 #include <gtk/gtkbutton.h>
25 #include <gtk/gtkstock.h>
26 #include <gtk/gtkversion.h>
28 #include "glyphs.h"
30 #include "desktop.h"
31 #include "document.h" // for sp_document_done()
32 #include "libnrtype/font-instance.h"
33 #include "sp-flowtext.h"
34 #include "sp-text.h"
35 #include "verbs.h"
36 #include "widgets/font-selector.h"
37 #include "text-editing.h"
39 namespace Inkscape {
40 namespace UI {
41 namespace Dialog {
44 GlyphsPanel &GlyphsPanel::getInstance()
45 {
46 return *new GlyphsPanel();
47 }
50 #if GLIB_CHECK_VERSION(2,14,0)
51 static std::map<GUnicodeScript, Glib::ustring> & getScriptToName()
52 {
53 static bool init = false;
54 static std::map<GUnicodeScript, Glib::ustring> mappings;
55 if (!init) {
56 init = true;
57 mappings[G_UNICODE_SCRIPT_INVALID_CODE] = _("all");
58 mappings[G_UNICODE_SCRIPT_COMMON] = _("common");
59 mappings[G_UNICODE_SCRIPT_INHERITED] = _("inherited");
60 mappings[G_UNICODE_SCRIPT_ARABIC] = _("Arabic");
61 mappings[G_UNICODE_SCRIPT_ARMENIAN] = _("Armenian");
62 mappings[G_UNICODE_SCRIPT_BENGALI] = _("Bengali");
63 mappings[G_UNICODE_SCRIPT_BOPOMOFO] = _("Bopomofo");
64 mappings[G_UNICODE_SCRIPT_CHEROKEE] = _("Cherokee");
65 mappings[G_UNICODE_SCRIPT_COPTIC] = _("Coptic");
66 mappings[G_UNICODE_SCRIPT_CYRILLIC] = _("Cyrillic");
67 mappings[G_UNICODE_SCRIPT_DESERET] = _("Deseret");
68 mappings[G_UNICODE_SCRIPT_DEVANAGARI] = _("Devanagari");
69 mappings[G_UNICODE_SCRIPT_ETHIOPIC] = _("Ethiopic");
70 mappings[G_UNICODE_SCRIPT_GEORGIAN] = _("Georgian");
71 mappings[G_UNICODE_SCRIPT_GOTHIC] = _("Gothic");
72 mappings[G_UNICODE_SCRIPT_GREEK] = _("Greek");
73 mappings[G_UNICODE_SCRIPT_GUJARATI] = _("Gujarati");
74 mappings[G_UNICODE_SCRIPT_GURMUKHI] = _("Gurmukhi");
75 mappings[G_UNICODE_SCRIPT_HAN] = _("Han");
76 mappings[G_UNICODE_SCRIPT_HANGUL] = _("Hangul");
77 mappings[G_UNICODE_SCRIPT_HEBREW] = _("Hebrew");
78 mappings[G_UNICODE_SCRIPT_HIRAGANA] = _("Hiragana");
79 mappings[G_UNICODE_SCRIPT_KANNADA] = _("Kannada");
80 mappings[G_UNICODE_SCRIPT_KATAKANA] = _("Katakana");
81 mappings[G_UNICODE_SCRIPT_KHMER] = _("Khmer");
82 mappings[G_UNICODE_SCRIPT_LAO] = _("Lao");
83 mappings[G_UNICODE_SCRIPT_LATIN] = _("Latin");
84 mappings[G_UNICODE_SCRIPT_MALAYALAM] = _("Malayalam");
85 mappings[G_UNICODE_SCRIPT_MONGOLIAN] = _("Mongolian");
86 mappings[G_UNICODE_SCRIPT_MYANMAR] = _("Myanmar");
87 mappings[G_UNICODE_SCRIPT_OGHAM] = _("Ogham");
88 mappings[G_UNICODE_SCRIPT_OLD_ITALIC] = _("Old Italic");
89 mappings[G_UNICODE_SCRIPT_ORIYA] = _("Oriya");
90 mappings[G_UNICODE_SCRIPT_RUNIC] = _("Runic");
91 mappings[G_UNICODE_SCRIPT_SINHALA] = _("Sinhala");
92 mappings[G_UNICODE_SCRIPT_SYRIAC] = _("Syriac");
93 mappings[G_UNICODE_SCRIPT_TAMIL] = _("Tamil");
94 mappings[G_UNICODE_SCRIPT_TELUGU] = _("Telugu");
95 mappings[G_UNICODE_SCRIPT_THAANA] = _("Thaana");
96 mappings[G_UNICODE_SCRIPT_THAI] = _("Thai");
97 mappings[G_UNICODE_SCRIPT_TIBETAN] = _("Tibetan");
98 mappings[G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL] = _("Canadian Aboriginal");
99 mappings[G_UNICODE_SCRIPT_YI] = _("Yi");
100 mappings[G_UNICODE_SCRIPT_TAGALOG] = _("Tagalog");
101 mappings[G_UNICODE_SCRIPT_HANUNOO] = _("Hanunoo");
102 mappings[G_UNICODE_SCRIPT_BUHID] = _("Buhid");
103 mappings[G_UNICODE_SCRIPT_TAGBANWA] = _("Tagbanwa");
104 mappings[G_UNICODE_SCRIPT_BRAILLE] = _("Braille");
105 mappings[G_UNICODE_SCRIPT_CYPRIOT] = _("Cypriot");
106 mappings[G_UNICODE_SCRIPT_LIMBU] = _("Limbu");
107 mappings[G_UNICODE_SCRIPT_OSMANYA] = _("Osmanya");
108 mappings[G_UNICODE_SCRIPT_SHAVIAN] = _("Shavian");
109 mappings[G_UNICODE_SCRIPT_LINEAR_B] = _("Linear B");
110 mappings[G_UNICODE_SCRIPT_TAI_LE] = _("Tai Le");
111 mappings[G_UNICODE_SCRIPT_UGARITIC] = _("Ugaritic");
112 mappings[G_UNICODE_SCRIPT_NEW_TAI_LUE] = _("New Tai Lue");
113 mappings[G_UNICODE_SCRIPT_BUGINESE] = _("Buginese");
114 mappings[G_UNICODE_SCRIPT_GLAGOLITIC] = _("Glagolitic");
115 mappings[G_UNICODE_SCRIPT_TIFINAGH] = _("Tifinagh");
116 mappings[G_UNICODE_SCRIPT_SYLOTI_NAGRI] = _("Syloti Nagri");
117 mappings[G_UNICODE_SCRIPT_OLD_PERSIAN] = _("Old Persian");
118 mappings[G_UNICODE_SCRIPT_KHAROSHTHI] = _("Kharoshthi");
119 mappings[G_UNICODE_SCRIPT_UNKNOWN] = _("unassigned");
120 mappings[G_UNICODE_SCRIPT_BALINESE] = _("Balinese");
121 mappings[G_UNICODE_SCRIPT_CUNEIFORM] = _("Cuneiform");
122 mappings[G_UNICODE_SCRIPT_PHOENICIAN] = _("Phoenician");
123 mappings[G_UNICODE_SCRIPT_PHAGS_PA] = _("Phags-pa");
124 mappings[G_UNICODE_SCRIPT_NKO] = _("N'Ko");
126 #if GLIB_CHECK_VERSION(2,14,0)
127 mappings[G_UNICODE_SCRIPT_KAYAH_LI] = _("Kayah Li");
128 mappings[G_UNICODE_SCRIPT_LEPCHA] = _("Lepcha");
129 mappings[G_UNICODE_SCRIPT_REJANG] = _("Rejang");
130 mappings[G_UNICODE_SCRIPT_SUNDANESE] = _("Sundanese");
131 mappings[G_UNICODE_SCRIPT_SAURASHTRA] = _("Saurashtra");
132 mappings[G_UNICODE_SCRIPT_CHAM] = _("Cham");
133 mappings[G_UNICODE_SCRIPT_OL_CHIKI] = _("Ol Chiki");
134 mappings[G_UNICODE_SCRIPT_VAI] = _("Vai");
135 mappings[G_UNICODE_SCRIPT_CARIAN] = _("Carian");
136 mappings[G_UNICODE_SCRIPT_LYCIAN] = _("Lycian");
137 mappings[G_UNICODE_SCRIPT_LYDIAN] = _("Lydian");
138 #endif // GLIB_CHECK_VERSION(2,14,0)
139 }
140 return mappings;
141 }
142 #endif // GLIB_CHECK_VERSION(2,14,0)
144 typedef std::pair<gunichar, gunichar> Range;
145 typedef std::pair<Range, Glib::ustring> NamedRange;
147 static std::vector<NamedRange> & getRanges()
148 {
149 static bool init = false;
150 static std::vector<NamedRange> ranges;
151 if (!init) {
152 init = true;
153 ranges.push_back(std::make_pair(std::make_pair(0x0000, 0xFFFD), _("all")));
154 ranges.push_back(std::make_pair(std::make_pair(0x0000, 0x007F), _("Basic Latin")));
155 ranges.push_back(std::make_pair(std::make_pair(0x0080, 0x00FF), _("Latin-1 Supplement")));
156 ranges.push_back(std::make_pair(std::make_pair(0x0100, 0x017F), _("Latin Extended-A")));
157 ranges.push_back(std::make_pair(std::make_pair(0x0180, 0x024F), _("Latin Extended-B")));
158 ranges.push_back(std::make_pair(std::make_pair(0x0250, 0x02AF), _("IPA Extensions")));
159 ranges.push_back(std::make_pair(std::make_pair(0x02B0, 0x02FF), _("Spacing Modifier Letters")));
160 ranges.push_back(std::make_pair(std::make_pair(0x0300, 0x036F), _("Combining Diacritical Marks")));
161 ranges.push_back(std::make_pair(std::make_pair(0x0370, 0x03FF), _("Greek and Coptic")));
162 ranges.push_back(std::make_pair(std::make_pair(0x0400, 0x04FF), _("Cyrillic")));
163 ranges.push_back(std::make_pair(std::make_pair(0x0500, 0x052F), _("Cyrillic Supplement")));
164 ranges.push_back(std::make_pair(std::make_pair(0x0530, 0x058F), _("Armenian")));
165 ranges.push_back(std::make_pair(std::make_pair(0x0590, 0x05FF), _("Hebrew")));
166 ranges.push_back(std::make_pair(std::make_pair(0x0600, 0x06FF), _("Arabic")));
167 ranges.push_back(std::make_pair(std::make_pair(0x0700, 0x074F), _("Syriac")));
168 ranges.push_back(std::make_pair(std::make_pair(0x0750, 0x077F), _("Arabic Supplement")));
169 ranges.push_back(std::make_pair(std::make_pair(0x0780, 0x07BF), _("Thaana")));
170 ranges.push_back(std::make_pair(std::make_pair(0x07C0, 0x07FF), _("NKo")));
171 ranges.push_back(std::make_pair(std::make_pair(0x0800, 0x083F), _("Samaritan")));
172 ranges.push_back(std::make_pair(std::make_pair(0x0900, 0x097F), _("Devanagari")));
173 ranges.push_back(std::make_pair(std::make_pair(0x0980, 0x09FF), _("Bengali")));
174 ranges.push_back(std::make_pair(std::make_pair(0x0A00, 0x0A7F), _("Gurmukhi")));
175 ranges.push_back(std::make_pair(std::make_pair(0x0A80, 0x0AFF), _("Gujarati")));
176 ranges.push_back(std::make_pair(std::make_pair(0x0B00, 0x0B7F), _("Oriya")));
177 ranges.push_back(std::make_pair(std::make_pair(0x0B80, 0x0BFF), _("Tamil")));
178 ranges.push_back(std::make_pair(std::make_pair(0x0C00, 0x0C7F), _("Telugu")));
179 ranges.push_back(std::make_pair(std::make_pair(0x0C80, 0x0CFF), _("Kannada")));
180 ranges.push_back(std::make_pair(std::make_pair(0x0D00, 0x0D7F), _("Malayalam")));
181 ranges.push_back(std::make_pair(std::make_pair(0x0D80, 0x0DFF), _("Sinhala")));
182 ranges.push_back(std::make_pair(std::make_pair(0x0E00, 0x0E7F), _("Thai")));
183 ranges.push_back(std::make_pair(std::make_pair(0x0E80, 0x0EFF), _("Lao")));
184 ranges.push_back(std::make_pair(std::make_pair(0x0F00, 0x0FFF), _("Tibetan")));
185 ranges.push_back(std::make_pair(std::make_pair(0x1000, 0x109F), _("Myanmar")));
186 ranges.push_back(std::make_pair(std::make_pair(0x10A0, 0x10FF), _("Georgian")));
187 ranges.push_back(std::make_pair(std::make_pair(0x1100, 0x11FF), _("Hangul Jamo")));
188 ranges.push_back(std::make_pair(std::make_pair(0x1200, 0x137F), _("Ethiopic")));
189 ranges.push_back(std::make_pair(std::make_pair(0x1380, 0x139F), _("Ethiopic Supplement")));
190 ranges.push_back(std::make_pair(std::make_pair(0x13A0, 0x13FF), _("Cherokee")));
191 ranges.push_back(std::make_pair(std::make_pair(0x1400, 0x167F), _("Unified Canadian Aboriginal Syllabics")));
192 ranges.push_back(std::make_pair(std::make_pair(0x1680, 0x169F), _("Ogham")));
193 ranges.push_back(std::make_pair(std::make_pair(0x16A0, 0x16FF), _("Runic")));
194 ranges.push_back(std::make_pair(std::make_pair(0x1700, 0x171F), _("Tagalog")));
195 ranges.push_back(std::make_pair(std::make_pair(0x1720, 0x173F), _("Hanunoo")));
196 ranges.push_back(std::make_pair(std::make_pair(0x1740, 0x175F), _("Buhid")));
197 ranges.push_back(std::make_pair(std::make_pair(0x1760, 0x177F), _("Tagbanwa")));
198 ranges.push_back(std::make_pair(std::make_pair(0x1780, 0x17FF), _("Khmer")));
199 ranges.push_back(std::make_pair(std::make_pair(0x1800, 0x18AF), _("Mongolian")));
200 ranges.push_back(std::make_pair(std::make_pair(0x18B0, 0x18FF), _("Unified Canadian Aboriginal Syllabics Extended")));
201 ranges.push_back(std::make_pair(std::make_pair(0x1900, 0x194F), _("Limbu")));
202 ranges.push_back(std::make_pair(std::make_pair(0x1950, 0x197F), _("Tai Le")));
203 ranges.push_back(std::make_pair(std::make_pair(0x1980, 0x19DF), _("New Tai Lue")));
204 ranges.push_back(std::make_pair(std::make_pair(0x19E0, 0x19FF), _("Khmer Symbols")));
205 ranges.push_back(std::make_pair(std::make_pair(0x1A00, 0x1A1F), _("Buginese")));
206 ranges.push_back(std::make_pair(std::make_pair(0x1A20, 0x1AAF), _("Tai Tham")));
207 ranges.push_back(std::make_pair(std::make_pair(0x1B00, 0x1B7F), _("Balinese")));
208 ranges.push_back(std::make_pair(std::make_pair(0x1B80, 0x1BBF), _("Sundanese")));
209 ranges.push_back(std::make_pair(std::make_pair(0x1C00, 0x1C4F), _("Lepcha")));
210 ranges.push_back(std::make_pair(std::make_pair(0x1C50, 0x1C7F), _("Ol Chiki")));
211 ranges.push_back(std::make_pair(std::make_pair(0x1CD0, 0x1CFF), _("Vedic Extensions")));
212 ranges.push_back(std::make_pair(std::make_pair(0x1D00, 0x1D7F), _("Phonetic Extensions")));
213 ranges.push_back(std::make_pair(std::make_pair(0x1D80, 0x1DBF), _("Phonetic Extensions Supplement")));
214 ranges.push_back(std::make_pair(std::make_pair(0x1DC0, 0x1DFF), _("Combining Diacritical Marks Supplement")));
215 ranges.push_back(std::make_pair(std::make_pair(0x1E00, 0x1EFF), _("Latin Extended Additional")));
216 ranges.push_back(std::make_pair(std::make_pair(0x1F00, 0x1FFF), _("Greek Extended")));
217 ranges.push_back(std::make_pair(std::make_pair(0x2000, 0x206F), _("General Punctuation")));
218 ranges.push_back(std::make_pair(std::make_pair(0x2070, 0x209F), _("Superscripts and Subscripts")));
219 ranges.push_back(std::make_pair(std::make_pair(0x20A0, 0x20CF), _("Currency Symbols")));
220 ranges.push_back(std::make_pair(std::make_pair(0x20D0, 0x20FF), _("Combining Diacritical Marks for Symbols")));
221 ranges.push_back(std::make_pair(std::make_pair(0x2100, 0x214F), _("Letterlike Symbols")));
222 ranges.push_back(std::make_pair(std::make_pair(0x2150, 0x218F), _("Number Forms")));
223 ranges.push_back(std::make_pair(std::make_pair(0x2190, 0x21FF), _("Arrows")));
224 ranges.push_back(std::make_pair(std::make_pair(0x2200, 0x22FF), _("Mathematical Operators")));
225 ranges.push_back(std::make_pair(std::make_pair(0x2300, 0x23FF), _("Miscellaneous Technical")));
226 ranges.push_back(std::make_pair(std::make_pair(0x2400, 0x243F), _("Control Pictures")));
227 ranges.push_back(std::make_pair(std::make_pair(0x2440, 0x245F), _("Optical Character Recognition")));
228 ranges.push_back(std::make_pair(std::make_pair(0x2460, 0x24FF), _("Enclosed Alphanumerics")));
229 ranges.push_back(std::make_pair(std::make_pair(0x2500, 0x257F), _("Box Drawing")));
230 ranges.push_back(std::make_pair(std::make_pair(0x2580, 0x259F), _("Block Elements")));
231 ranges.push_back(std::make_pair(std::make_pair(0x25A0, 0x25FF), _("Geometric Shapes")));
232 ranges.push_back(std::make_pair(std::make_pair(0x2600, 0x26FF), _("Miscellaneous Symbols")));
233 ranges.push_back(std::make_pair(std::make_pair(0x2700, 0x27BF), _("Dingbats")));
234 ranges.push_back(std::make_pair(std::make_pair(0x27C0, 0x27EF), _("Miscellaneous Mathematical Symbols-A")));
235 ranges.push_back(std::make_pair(std::make_pair(0x27F0, 0x27FF), _("Supplemental Arrows-A")));
236 ranges.push_back(std::make_pair(std::make_pair(0x2800, 0x28FF), _("Braille Patterns")));
237 ranges.push_back(std::make_pair(std::make_pair(0x2900, 0x297F), _("Supplemental Arrows-B")));
238 ranges.push_back(std::make_pair(std::make_pair(0x2980, 0x29FF), _("Miscellaneous Mathematical Symbols-B")));
239 ranges.push_back(std::make_pair(std::make_pair(0x2A00, 0x2AFF), _("Supplemental Mathematical Operators")));
240 ranges.push_back(std::make_pair(std::make_pair(0x2B00, 0x2BFF), _("Miscellaneous Symbols and Arrows")));
241 ranges.push_back(std::make_pair(std::make_pair(0x2C00, 0x2C5F), _("Glagolitic")));
242 ranges.push_back(std::make_pair(std::make_pair(0x2C60, 0x2C7F), _("Latin Extended-C")));
243 ranges.push_back(std::make_pair(std::make_pair(0x2C80, 0x2CFF), _("Coptic")));
244 ranges.push_back(std::make_pair(std::make_pair(0x2D00, 0x2D2F), _("Georgian Supplement")));
245 ranges.push_back(std::make_pair(std::make_pair(0x2D30, 0x2D7F), _("Tifinagh")));
246 ranges.push_back(std::make_pair(std::make_pair(0x2D80, 0x2DDF), _("Ethiopic Extended")));
247 ranges.push_back(std::make_pair(std::make_pair(0x2DE0, 0x2DFF), _("Cyrillic Extended-A")));
248 ranges.push_back(std::make_pair(std::make_pair(0x2E00, 0x2E7F), _("Supplemental Punctuation")));
249 ranges.push_back(std::make_pair(std::make_pair(0x2E80, 0x2EFF), _("CJK Radicals Supplement")));
250 ranges.push_back(std::make_pair(std::make_pair(0x2F00, 0x2FDF), _("Kangxi Radicals")));
251 ranges.push_back(std::make_pair(std::make_pair(0x2FF0, 0x2FFF), _("Ideographic Description Characters")));
252 ranges.push_back(std::make_pair(std::make_pair(0x3000, 0x303F), _("CJK Symbols and Punctuation")));
253 ranges.push_back(std::make_pair(std::make_pair(0x3040, 0x309F), _("Hiragana")));
254 ranges.push_back(std::make_pair(std::make_pair(0x30A0, 0x30FF), _("Katakana")));
255 ranges.push_back(std::make_pair(std::make_pair(0x3100, 0x312F), _("Bopomofo")));
256 ranges.push_back(std::make_pair(std::make_pair(0x3130, 0x318F), _("Hangul Compatibility Jamo")));
257 ranges.push_back(std::make_pair(std::make_pair(0x3190, 0x319F), _("Kanbun")));
258 ranges.push_back(std::make_pair(std::make_pair(0x31A0, 0x31BF), _("Bopomofo Extended")));
259 ranges.push_back(std::make_pair(std::make_pair(0x31C0, 0x31EF), _("CJK Strokes")));
260 ranges.push_back(std::make_pair(std::make_pair(0x31F0, 0x31FF), _("Katakana Phonetic Extensions")));
261 ranges.push_back(std::make_pair(std::make_pair(0x3200, 0x32FF), _("Enclosed CJK Letters and Months")));
262 ranges.push_back(std::make_pair(std::make_pair(0x3300, 0x33FF), _("CJK Compatibility")));
263 ranges.push_back(std::make_pair(std::make_pair(0x3400, 0x4DBF), _("CJK Unified Ideographs Extension A")));
264 ranges.push_back(std::make_pair(std::make_pair(0x4DC0, 0x4DFF), _("Yijing Hexagram Symbols")));
265 ranges.push_back(std::make_pair(std::make_pair(0x4E00, 0x9FFF), _("CJK Unified Ideographs")));
266 ranges.push_back(std::make_pair(std::make_pair(0xA000, 0xA48F), _("Yi Syllables")));
267 ranges.push_back(std::make_pair(std::make_pair(0xA490, 0xA4CF), _("Yi Radicals")));
268 ranges.push_back(std::make_pair(std::make_pair(0xA4D0, 0xA4FF), _("Lisu")));
269 ranges.push_back(std::make_pair(std::make_pair(0xA500, 0xA63F), _("Vai")));
270 ranges.push_back(std::make_pair(std::make_pair(0xA640, 0xA69F), _("Cyrillic Extended-B")));
271 ranges.push_back(std::make_pair(std::make_pair(0xA6A0, 0xA6FF), _("Bamum")));
272 ranges.push_back(std::make_pair(std::make_pair(0xA700, 0xA71F), _("Modifier Tone Letters")));
273 ranges.push_back(std::make_pair(std::make_pair(0xA720, 0xA7FF), _("Latin Extended-D")));
274 ranges.push_back(std::make_pair(std::make_pair(0xA800, 0xA82F), _("Syloti Nagri")));
275 ranges.push_back(std::make_pair(std::make_pair(0xA830, 0xA83F), _("Common Indic Number Forms")));
276 ranges.push_back(std::make_pair(std::make_pair(0xA840, 0xA87F), _("Phags-pa")));
277 ranges.push_back(std::make_pair(std::make_pair(0xA880, 0xA8DF), _("Saurashtra")));
278 ranges.push_back(std::make_pair(std::make_pair(0xA8E0, 0xA8FF), _("Devanagari Extended")));
279 ranges.push_back(std::make_pair(std::make_pair(0xA900, 0xA92F), _("Kayah Li")));
280 ranges.push_back(std::make_pair(std::make_pair(0xA930, 0xA95F), _("Rejang")));
281 ranges.push_back(std::make_pair(std::make_pair(0xA960, 0xA97F), _("Hangul Jamo Extended-A")));
282 ranges.push_back(std::make_pair(std::make_pair(0xA980, 0xA9DF), _("Javanese")));
283 ranges.push_back(std::make_pair(std::make_pair(0xAA00, 0xAA5F), _("Cham")));
284 ranges.push_back(std::make_pair(std::make_pair(0xAA60, 0xAA7F), _("Myanmar Extended-A")));
285 ranges.push_back(std::make_pair(std::make_pair(0xAA80, 0xAADF), _("Tai Viet")));
286 ranges.push_back(std::make_pair(std::make_pair(0xABC0, 0xABFF), _("Meetei Mayek")));
287 ranges.push_back(std::make_pair(std::make_pair(0xAC00, 0xD7AF), _("Hangul Syllables")));
288 ranges.push_back(std::make_pair(std::make_pair(0xD7B0, 0xD7FF), _("Hangul Jamo Extended-B")));
289 ranges.push_back(std::make_pair(std::make_pair(0xD800, 0xDB7F), _("High Surrogates")));
290 ranges.push_back(std::make_pair(std::make_pair(0xDB80, 0xDBFF), _("High Private Use Surrogates")));
291 ranges.push_back(std::make_pair(std::make_pair(0xDC00, 0xDFFF), _("Low Surrogates")));
292 ranges.push_back(std::make_pair(std::make_pair(0xE000, 0xF8FF), _("Private Use Area")));
293 ranges.push_back(std::make_pair(std::make_pair(0xF900, 0xFAFF), _("CJK Compatibility Ideographs")));
294 ranges.push_back(std::make_pair(std::make_pair(0xFB00, 0xFB4F), _("Alphabetic Presentation Forms")));
295 ranges.push_back(std::make_pair(std::make_pair(0xFB50, 0xFDFF), _("Arabic Presentation Forms-A")));
296 ranges.push_back(std::make_pair(std::make_pair(0xFE00, 0xFE0F), _("Variation Selectors")));
297 ranges.push_back(std::make_pair(std::make_pair(0xFE10, 0xFE1F), _("Vertical Forms")));
298 ranges.push_back(std::make_pair(std::make_pair(0xFE20, 0xFE2F), _("Combining Half Marks")));
299 ranges.push_back(std::make_pair(std::make_pair(0xFE30, 0xFE4F), _("CJK Compatibility Forms")));
300 ranges.push_back(std::make_pair(std::make_pair(0xFE50, 0xFE6F), _("Small Form Variants")));
301 ranges.push_back(std::make_pair(std::make_pair(0xFE70, 0xFEFF), _("Arabic Presentation Forms-B")));
302 ranges.push_back(std::make_pair(std::make_pair(0xFF00, 0xFFEF), _("Halfwidth and Fullwidth Forms")));
303 ranges.push_back(std::make_pair(std::make_pair(0xFFF0, 0xFFFF), _("Specials")));
304 }
306 return ranges;
307 }
309 class GlyphColumns : public Gtk::TreeModel::ColumnRecord
310 {
311 public:
312 Gtk::TreeModelColumn<gunichar> code;
313 Gtk::TreeModelColumn<Glib::ustring> name;
315 GlyphColumns()
316 {
317 add(code);
318 add(name);
319 }
320 };
322 GlyphColumns *GlyphsPanel::getColumns()
323 {
324 static GlyphColumns *columns = new GlyphColumns();
326 return columns;
327 }
329 /**
330 * Constructor
331 */
332 GlyphsPanel::GlyphsPanel(gchar const *prefsPath) :
333 Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_GLYPHS, "", false),
334 store(Gtk::ListStore::create(*getColumns())),
335 iconView(0),
336 entry(0),
337 label(0),
338 insertBtn(0),
339 #if GLIB_CHECK_VERSION(2,14,0)
340 scriptCombo(0),
341 #endif // GLIB_CHECK_VERSION(2,14,0)
342 fsel(0),
343 targetDesktop(0),
344 deskTrack(),
345 instanceConns(),
346 desktopConns()
347 {
348 Gtk::Table *table = new Gtk::Table(3, 1, false);
349 _getContents()->pack_start(*Gtk::manage(table), Gtk::PACK_EXPAND_WIDGET);
350 guint row = 0;
352 // -------------------------------
354 GtkWidget *fontsel = sp_font_selector_new();
355 fsel = SP_FONT_SELECTOR(fontsel);
356 sp_font_selector_set_font(fsel, sp_font_selector_get_font(fsel), 12.0);
358 g_signal_connect( G_OBJECT(fontsel), "font_set", G_CALLBACK(fontChangeCB), this );
360 table->attach(*Gtk::manage(Glib::wrap(fontsel)),
361 0, 3, row, row + 1,
362 Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL);
363 row++;
366 // -------------------------------
368 #if GLIB_CHECK_VERSION(2,14,0)
369 {
370 Gtk::Label *label = new Gtk::Label(_("Script: "));
371 table->attach( *Gtk::manage(label),
372 0, 1, row, row + 1,
373 Gtk::SHRINK, Gtk::SHRINK);
375 scriptCombo = new Gtk::ComboBoxText();
376 for (std::map<GUnicodeScript, Glib::ustring>::iterator it = getScriptToName().begin(); it != getScriptToName().end(); ++it)
377 {
378 scriptCombo->append_text(it->second);
379 }
381 scriptCombo->set_active_text(getScriptToName()[G_UNICODE_SCRIPT_INVALID_CODE]);
382 sigc::connection conn = scriptCombo->signal_changed().connect(sigc::mem_fun(*this, &GlyphsPanel::rebuild));
383 instanceConns.push_back(conn);
385 Gtk::Alignment *align = new Gtk::Alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, 0.0, 0.0);
386 align->add(*Gtk::manage(scriptCombo));
387 table->attach( *Gtk::manage(align),
388 1, 2, row, row + 1,
389 Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
390 }
392 row++;
393 #endif // GLIB_CHECK_VERSION(2,14,0)
395 // -------------------------------
397 {
398 Gtk::Label *label = new Gtk::Label(_("Range: "));
399 table->attach( *Gtk::manage(label),
400 0, 1, row, row + 1,
401 Gtk::SHRINK, Gtk::SHRINK);
403 rangeCombo = new Gtk::ComboBoxText();
404 for ( std::vector<NamedRange>::iterator it = getRanges().begin(); it != getRanges().end(); ++it ) {
405 rangeCombo->append_text(it->second);
406 }
408 rangeCombo->set_active_text(getRanges()[1].second);
409 sigc::connection conn = rangeCombo->signal_changed().connect(sigc::mem_fun(*this, &GlyphsPanel::rebuild));
410 instanceConns.push_back(conn);
412 Gtk::Alignment *align = new Gtk::Alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, 0.0, 0.0);
413 align->add(*Gtk::manage(rangeCombo));
414 table->attach( *Gtk::manage(align),
415 1, 2, row, row + 1,
416 Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
417 }
419 row++;
421 // -------------------------------
423 GlyphColumns *columns = getColumns();
425 iconView = new Gtk::IconView(store);
426 iconView->set_text_column(columns->name);
427 //iconView->set_columns(16);
429 sigc::connection conn;
430 conn = iconView->signal_item_activated().connect(sigc::mem_fun(*this, &GlyphsPanel::glyphActivated));
431 instanceConns.push_back(conn);
432 conn = iconView->signal_selection_changed().connect(sigc::mem_fun(*this, &GlyphsPanel::glyphSelectionChanged));
433 instanceConns.push_back(conn);
436 Gtk::ScrolledWindow *scroller = new Gtk::ScrolledWindow();
437 scroller->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
438 scroller->add(*Gtk::manage(iconView));
439 table->attach(*Gtk::manage(scroller),
440 0, 3, row, row + 1,
441 Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL);
442 row++;
444 // -------------------------------
446 Gtk::HBox *box = new Gtk::HBox();
448 entry = new Gtk::Entry();
449 conn = entry->signal_changed().connect(sigc::mem_fun(*this, &GlyphsPanel::calcCanInsert));
450 instanceConns.push_back(conn);
451 entry->set_width_chars(18);
452 box->pack_start(*Gtk::manage(entry), Gtk::PACK_SHRINK);
454 Gtk::Label *pad = new Gtk::Label(" ");
455 box->pack_start(*Gtk::manage(pad), Gtk::PACK_SHRINK);
457 label = new Gtk::Label(" ");
458 box->pack_start(*Gtk::manage(label), Gtk::PACK_SHRINK);
460 pad = new Gtk::Label("");
461 box->pack_start(*Gtk::manage(pad), Gtk::PACK_EXPAND_WIDGET);
463 insertBtn = new Gtk::Button(_("Append"));
464 conn = insertBtn->signal_clicked().connect(sigc::mem_fun(*this, &GlyphsPanel::insertText));
465 instanceConns.push_back(conn);
466 #if GTK_CHECK_VERSION(2,18,0)
467 //gtkmm 2.18
468 insertBtn->set_can_default();
469 #endif
470 insertBtn->set_sensitive(false);
472 box->pack_end(*Gtk::manage(insertBtn), Gtk::PACK_SHRINK);
474 table->attach( *Gtk::manage(box),
475 0, 3, row, row + 1,
476 Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK);
477 row++;
479 // -------------------------------
482 show_all_children();
484 restorePanelPrefs();
486 // Connect this up last
487 conn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &GlyphsPanel::setTargetDesktop) );
488 instanceConns.push_back(conn);
489 deskTrack.connect(GTK_WIDGET(gobj()));
490 }
492 GlyphsPanel::~GlyphsPanel()
493 {
494 for (std::vector<sigc::connection>::iterator it = instanceConns.begin(); it != instanceConns.end(); ++it) {
495 it->disconnect();
496 }
497 instanceConns.clear();
498 for (std::vector<sigc::connection>::iterator it = desktopConns.begin(); it != desktopConns.end(); ++it) {
499 it->disconnect();
500 }
501 desktopConns.clear();
502 }
505 void GlyphsPanel::setDesktop(SPDesktop *desktop)
506 {
507 Panel::setDesktop(desktop);
508 deskTrack.setBase(desktop);
509 }
511 void GlyphsPanel::setTargetDesktop(SPDesktop *desktop)
512 {
513 if (targetDesktop != desktop) {
514 if (targetDesktop) {
515 for (std::vector<sigc::connection>::iterator it = desktopConns.begin(); it != desktopConns.end(); ++it) {
516 it->disconnect();
517 }
518 desktopConns.clear();
519 }
521 targetDesktop = desktop;
523 if (targetDesktop && targetDesktop->selection) {
524 sigc::connection conn = desktop->selection->connectChanged(sigc::hide(sigc::bind(sigc::mem_fun(*this, &GlyphsPanel::readSelection), true, true)));
525 desktopConns.push_back(conn);
527 // Text selection within selected items has changed:
528 conn = desktop->connectToolSubselectionChanged(sigc::hide(sigc::bind(sigc::mem_fun(*this, &GlyphsPanel::readSelection), true, false)));
529 desktopConns.push_back(conn);
531 // Must check flags, so can't call performUpdate() directly.
532 conn = desktop->selection->connectModified(sigc::hide<0>(sigc::mem_fun(*this, &GlyphsPanel::selectionModifiedCB)));
533 desktopConns.push_back(conn);
535 readSelection(true, true);
536 }
537 }
538 }
540 void GlyphsPanel::insertText()
541 {
542 SPItem *textItem = 0;
543 for (const GSList *item = targetDesktop->selection->itemList(); item; item = item->next ) {
544 if (SP_IS_TEXT(item->data) || SP_IS_FLOWTEXT(item->data)) {
545 textItem = SP_ITEM(item->data);
546 break;
547 }
548 }
550 if (textItem) {
551 Glib::ustring glyphs;
552 if (entry->get_text_length() > 0) {
553 glyphs = entry->get_text();
554 } else {
555 Gtk::IconView::ArrayHandle_TreePaths itemArray = iconView->get_selected_items();
556 if (!itemArray.empty()) {
557 Gtk::TreeModel::Path const & path = *itemArray.begin();
558 Gtk::ListStore::iterator row = store->get_iter(path);
559 gunichar ch = (*row)[getColumns()->code];
560 glyphs = ch;
561 }
562 }
564 if (!glyphs.empty()) {
565 Glib::ustring combined;
566 gchar *str = sp_te_get_string_multiline(textItem);
567 if (str) {
568 combined = str;
569 g_free(str);
570 str = 0;
571 }
572 combined += glyphs;
573 sp_te_set_repr_text_multiline(textItem, combined.c_str());
574 sp_document_done(targetDesktop->doc(), SP_VERB_CONTEXT_TEXT, _("Append text"));
575 }
576 }
577 }
579 void GlyphsPanel::glyphActivated(Gtk::TreeModel::Path const & path)
580 {
581 Gtk::ListStore::iterator row = store->get_iter(path);
582 gunichar ch = (*row)[getColumns()->code];
583 Glib::ustring tmp;
584 tmp += ch;
586 int startPos = 0;
587 int endPos = 0;
588 if (entry->get_selection_bounds(startPos, endPos)) {
589 // there was something selected.
590 entry->delete_text(startPos, endPos);
591 }
592 startPos = entry->get_position();
593 entry->insert_text(tmp, -1, startPos);
594 entry->set_position(startPos);
595 }
597 void GlyphsPanel::glyphSelectionChanged()
598 {
599 Gtk::IconView::ArrayHandle_TreePaths itemArray = iconView->get_selected_items();
600 if (itemArray.empty()) {
601 label->set_text(" ");
602 } else {
603 Gtk::TreeModel::Path const & path = *itemArray.begin();
604 Gtk::ListStore::iterator row = store->get_iter(path);
605 gunichar ch = (*row)[getColumns()->code];
608 Glib::ustring scriptName;
609 #if GLIB_CHECK_VERSION(2,14,0)
610 GUnicodeScript script = g_unichar_get_script(ch);
611 std::map<GUnicodeScript, Glib::ustring> mappings = getScriptToName();
612 if (mappings.find(script) != mappings.end()) {
613 scriptName = mappings[script];
614 }
615 #endif
616 gchar * tmp = g_strdup_printf("U+%04X %s", ch, scriptName.c_str());
617 label->set_text(tmp);
618 }
619 calcCanInsert();
620 }
622 void GlyphsPanel::fontChangeCB(SPFontSelector * /*fontsel*/, font_instance * /*font*/, GlyphsPanel *self)
623 {
624 if (self) {
625 self->rebuild();
626 }
627 }
629 void GlyphsPanel::selectionModifiedCB(guint flags)
630 {
631 bool style = ((flags & ( SP_OBJECT_CHILD_MODIFIED_FLAG |
632 SP_OBJECT_STYLE_MODIFIED_FLAG )) != 0 );
634 bool content = ((flags & ( SP_OBJECT_CHILD_MODIFIED_FLAG |
635 SP_TEXT_CONTENT_MODIFIED_FLAG )) != 0 );
637 readSelection(style, content);
638 }
640 void GlyphsPanel::calcCanInsert()
641 {
642 int items = 0;
643 for (const GSList *item = targetDesktop->selection->itemList(); item; item = item->next ) {
644 if (SP_IS_TEXT(item->data) || SP_IS_FLOWTEXT(item->data)) {
645 ++items;
646 }
647 }
649 bool enable = (items == 1);
650 if (enable) {
651 enable &= (!iconView->get_selected_items().empty()
652 || (entry->get_text_length() > 0));
653 }
655 if (enable != insertBtn->is_sensitive()) {
656 insertBtn->set_sensitive(enable);
657 }
658 }
660 void GlyphsPanel::readSelection( bool updateStyle, bool /*updateContent*/ )
661 {
662 calcCanInsert();
664 if (targetDesktop && updateStyle) {
665 //SPStyle *query = sp_style_new(SP_ACTIVE_DOCUMENT);
667 //int result_family = sp_desktop_query_style(targetDesktop, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
668 //int result_style = sp_desktop_query_style(targetDesktop, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
669 //int result_numbers = sp_desktop_query_style(targetDesktop, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
671 //sp_style_unref(query);
672 }
673 }
676 void GlyphsPanel::rebuild()
677 {
678 font_instance *font = fsel ? sp_font_selector_get_font(fsel) : 0;
679 if (font) {
680 //double sp_font_selector_get_size (SPFontSelector *fsel);
682 #if GLIB_CHECK_VERSION(2,14,0)
683 GUnicodeScript script = G_UNICODE_SCRIPT_INVALID_CODE;
684 Glib::ustring scriptName = scriptCombo->get_active_text();
685 std::map<GUnicodeScript, Glib::ustring> items = getScriptToName();
686 for (std::map<GUnicodeScript, Glib::ustring>::iterator it = items.begin(); it != items.end(); ++it) {
687 if (scriptName == it->second) {
688 script = it->first;
689 break;
690 }
691 }
692 #endif // GLIB_CHECK_VERSION(2,14,0)
694 // Disconnect the model while we update it. Simple work-around for 5x+ performance boost.
695 Glib::RefPtr<Gtk::ListStore> tmp = Gtk::ListStore::create(*getColumns());
696 iconView->set_model(tmp);
698 gunichar lower = 0x0001;
699 gunichar upper = 0xFFFD;
700 int active = rangeCombo->get_active_row_number();
701 if (active >= 0) {
702 lower = getRanges()[active].first.first;
703 upper = getRanges()[active].first.second;
704 }
705 std::vector<gunichar> present;
706 for (gunichar ch = lower; ch <= upper; ch++) {
707 int glyphId = font->MapUnicodeChar(ch);
708 if (glyphId > 0) {
709 #if GLIB_CHECK_VERSION(2,14,0)
710 if ((script == G_UNICODE_SCRIPT_INVALID_CODE) || (script == g_unichar_get_script(ch))) {
711 present.push_back(ch);
712 }
713 #else
714 present.push_back(ch);
715 #endif
716 }
717 }
719 GlyphColumns *columns = getColumns();
720 store->clear();
721 for (std::vector<gunichar>::iterator it = present.begin(); it != present.end(); ++it)
722 {
723 Gtk::ListStore::iterator row = store->append();
724 Glib::ustring tmp;
725 tmp += *it;
726 (*row)[columns->code] = *it;
727 (*row)[columns->name] = tmp;
728 }
730 // Reconnect the model once it has been updated:
731 iconView->set_model(store);
732 }
733 }
736 } // namespace Dialogs
737 } // namespace UI
738 } // namespace Inkscape
740 /*
741 Local Variables:
742 mode:c++
743 c-file-style:"stroustrup"
744 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
745 indent-tabs-mode:nil
746 fill-column:99
747 End:
748 */
749 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :