Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
font-variants.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Author:
4 * Tavmjong Bah <tavmjong@free.fr>
5 *
6 * Copyright (C) 2015, 2018 Tavmong Bah
7 *
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10
11#include "font-variants.h"
12
13#include <glibmm/i18n.h>
14#include <glibmm/markup.h>
15#include <glibmm/regex.h>
16#include <gtkmm/flowbox.h>
17#include <gtkmm/scrolledwindow.h>
20
21// For updating from selection
22#include "desktop.h"
23#include "object/sp-text.h"
24#include "ui/pack.h"
25#include "ui/util.h"
26
27namespace Inkscape::UI::Widget {
28
29// A simple class to handle UI for one feature. We could of derived this from Gtk::HBox but by
30// attaching widgets directly to Gtk::Grid, we keep columns lined up (which may or may not be a
31// good thing).
32class Feature
33{
34public:
35 Feature(Glib::ustring const &name, OTSubstitution const &glyphs, int options, Glib::ustring family, Gtk::Grid& grid, int &row, FontVariants* parent)
36 : _name (name)
37 {
38 auto const table_name = Gtk::make_managed<Gtk::Label>();
39 table_name->set_markup ("\"" + name + "\" ");
40
41 grid.attach (*table_name, 0, row, 1, 1);
42
43 Gtk::FlowBox* flow_box = nullptr;
44 Gtk::ScrolledWindow* scrolled_window = nullptr;
45 if (options > 2) {
46 // If there are more than 2 option, pack them into a flowbox instead of directly putting them in the grid.
47 // Some fonts might have a table with many options (Bungee Hairline table 'ornm' has 113 entries).
48 flow_box = Gtk::make_managed<Gtk::FlowBox>();
49 flow_box->set_selection_mode(); // Turn off selection
50 flow_box->set_homogeneous();
51 flow_box->set_max_children_per_line (100); // Override default value
52 flow_box->set_min_children_per_line (10); // Override default value
53
54 // We pack this into a scrollbar... otherwise the minimum height is set to what is required to fit all
55 // flow box children into the flow box when the flow box has minimum width. (Crazy if you ask me!)
56 scrolled_window = Gtk::make_managed<Gtk::ScrolledWindow>();
57 scrolled_window->set_policy (Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
58 scrolled_window->set_child(*flow_box);
59 }
60
61 Gtk::CheckButton *group = nullptr;
62 for (int i = 0; i < options; ++i) {
63 // Create radio button and create or add to button group.
64 auto const button = Gtk::make_managed<Gtk::CheckButton>();
65 if (i == 0) {
66 group = button;
67 } else {
68 button->set_group(*group);
69 }
70 button->signal_toggled().connect ( sigc::mem_fun(*parent, &FontVariants::feature_callback) );
71 buttons.push_back (button);
72
73 // Create label.
74 auto const label = Gtk::make_managed<Gtk::Label>();
75
76 // Restrict label width (some fonts have lots of alternatives).
77 label->set_wrap( true );
78 label->set_wrap_mode( Pango::WrapMode::WORD_CHAR );
79 label->set_ellipsize( Pango::EllipsizeMode::END );
80 label->set_lines(3);
81 label->set_hexpand();
82
83 Glib::ustring markup;
84 markup += "<span font_family='";
85 markup += family;
86 markup += "' font_features='";
87 markup += name;
88 markup += " ";
89 markup += std::to_string (i);
90 markup += "'>";
91 markup += Glib::Markup::escape_text (glyphs.input);
92 markup += "</span>";
93 label->set_markup (markup);
94
95 // Add button and label to widget
96 if (!flow_box) {
97 // Attach directly to grid (keeps things aligned row-to-row).
98 grid.attach (*button, 2*i+1, row, 1, 1);
99 grid.attach (*label, 2*i+2, row, 1, 1);
100 } else {
101 // Pack into FlowBox
102
103 // Pack button and label into a box so they stay together.
104 auto const box = Gtk::make_managed<Gtk::Box>();
105 box->append(*button);
106 box->append(*label);
107
108 flow_box->append(*box);
109 }
110 }
111
112 if (scrolled_window) {
113 grid.attach (*scrolled_window, 1, row, 4, 1);
114 }
115 }
116
117 Glib::ustring
118 get_css()
119 {
120 int i = 0;
121 for (auto b: buttons) {
122 if (b->get_active()) {
123 if (i == 0) {
124 // Features are always off by default (for those handled here).
125 return "";
126 } else if (i == 1) {
127 // Feature without value has implied value of 1.
128 return ("\"" + _name + "\", ");
129 } else {
130 // Feature with value greater than 1 must be explicitly set.
131 return ("\"" + _name + "\" " + std::to_string (i) + ", ");
132 }
133 }
134 ++i;
135 }
136 return "";
137 }
138
139 void
140 set_active(int i)
141 {
142 if (i < buttons.size()) {
143 buttons[i]->set_active();
144 }
145 }
146
147private:
148 Glib::ustring _name;
149 std::vector<Gtk::CheckButton *> buttons;
150};
151
153 Gtk::Box (Gtk::Orientation::VERTICAL),
154 _ligatures_frame ( Glib::ustring(C_("Font feature", "Ligatures" )) ),
155 _ligatures_common ( Glib::ustring(C_("Font feature", "Common" )) ),
156 _ligatures_discretionary ( Glib::ustring(C_("Font feature", "Discretionary")) ),
157 _ligatures_historical ( Glib::ustring(C_("Font feature", "Historical" )) ),
158 _ligatures_contextual ( Glib::ustring(C_("Font feature", "Contextual" )) ),
159
160 _position_frame ( Glib::ustring(C_("Font feature", "Position" )) ),
161 _position_normal ( Glib::ustring(C_("Font feature", "Normal" )) ),
162 _position_sub ( Glib::ustring(C_("Font feature", "Subscript" )) ),
163 _position_super ( Glib::ustring(C_("Font feature", "Superscript" )) ),
164
165 _caps_frame ( Glib::ustring(C_("Font feature", "Capitals" )) ),
166 _caps_normal ( Glib::ustring(C_("Font feature", "Normal" )) ),
167 _caps_small ( Glib::ustring(C_("Font feature", "Small" )) ),
168 _caps_all_small ( Glib::ustring(C_("Font feature", "All small" )) ),
169 _caps_petite ( Glib::ustring(C_("Font feature", "Petite" )) ),
170 _caps_all_petite ( Glib::ustring(C_("Font feature", "All petite" )) ),
171 _caps_unicase ( Glib::ustring(C_("Font feature", "Unicase" )) ),
172 _caps_titling ( Glib::ustring(C_("Font feature", "Titling" )) ),
173
174 _numeric_frame ( Glib::ustring(C_("Font feature", "Numeric" )) ),
175 _numeric_lining ( Glib::ustring(C_("Font feature", "Lining" )) ),
176 _numeric_old_style ( Glib::ustring(C_("Font feature", "Old Style" )) ),
177 _numeric_default_style ( Glib::ustring(C_("Font feature", "Default Style")) ),
178 _numeric_proportional ( Glib::ustring(C_("Font feature", "Proportional" )) ),
179 _numeric_tabular ( Glib::ustring(C_("Font feature", "Tabular" )) ),
180 _numeric_default_width ( Glib::ustring(C_("Font feature", "Default Width")) ),
181 _numeric_diagonal ( Glib::ustring(C_("Font feature", "Diagonal" )) ),
182 _numeric_stacked ( Glib::ustring(C_("Font feature", "Stacked" )) ),
183 _numeric_default_fractions( Glib::ustring(C_("Font feature", "Default Fractions")) ),
184 _numeric_ordinal ( Glib::ustring(C_("Font feature", "Ordinal" )) ),
185 _numeric_slashed_zero ( Glib::ustring(C_("Font feature", "Slashed Zero" )) ),
186
187 _asian_frame ( Glib::ustring(C_("Font feature", "East Asian" )) ),
188 _asian_default_variant ( Glib::ustring(C_("Font feature", "Default" )) ),
189 _asian_jis78 ( Glib::ustring(C_("Font feature", "JIS78" )) ),
190 _asian_jis83 ( Glib::ustring(C_("Font feature", "JIS83" )) ),
191 _asian_jis90 ( Glib::ustring(C_("Font feature", "JIS90" )) ),
192 _asian_jis04 ( Glib::ustring(C_("Font feature", "JIS04" )) ),
193 _asian_simplified ( Glib::ustring(C_("Font feature", "Simplified" )) ),
194 _asian_traditional ( Glib::ustring(C_("Font feature", "Traditional" )) ),
195 _asian_default_width ( Glib::ustring(C_("Font feature", "Default" )) ),
196 _asian_full_width ( Glib::ustring(C_("Font feature", "Full Width" )) ),
197 _asian_proportional_width ( Glib::ustring(C_("Font feature", "Proportional" )) ),
198 _asian_ruby ( Glib::ustring(C_("Font feature", "Ruby" )) ),
199
200 _feature_frame ( Glib::ustring(C_("Font feature", "Feature Settings")) ),
201 _feature_label ( Glib::ustring(C_("Font feature", "Selection has different Feature Settings!")) ),
202
203 _ligatures_changed( false ),
204 _position_changed( false ),
205 _caps_changed( false ),
206 _numeric_changed( false ),
207 _asian_changed( false ),
208 _feature_vbox(Gtk::Orientation::VERTICAL)
209
210{
211
212 set_name ( "FontVariants" );
213
214 // Ligatures --------------------------
215
216 // Add tooltips
217 _ligatures_common.set_tooltip_text(
218 _("Common ligatures. On by default. OpenType tables: 'liga', 'clig'"));
219 _ligatures_discretionary.set_tooltip_text(
220 _("Discretionary ligatures. Off by default. OpenType table: 'dlig'"));
221 _ligatures_historical.set_tooltip_text(
222 _("Historical ligatures. Off by default. OpenType table: 'hlig'"));
223 _ligatures_contextual.set_tooltip_text(
224 _("Contextual forms. On by default. OpenType table: 'calt'"));
225
226 // Add signals
227 _ligatures_common.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) );
228 _ligatures_discretionary.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) );
229 _ligatures_historical.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) );
230 _ligatures_contextual.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) );
231
232 // Restrict label widths (some fonts have lots of ligatures). Must also set ellipsize mode.
233 Gtk::Label* labels[] = {
238 };
239 for (auto label : labels) {
240 // char limit - not really needed, since number of lines is restricted
241 label->set_max_width_chars(999);
242 // show ellipsis when text overflows
243 label->set_ellipsize(Pango::EllipsizeMode::END);
244 // up to 5 lines
245 label->set_lines(5);
246 // multiline
247 label->set_wrap();
248 // break it as needed
249 label->set_wrap_mode(Pango::WrapMode::WORD_CHAR);
250 }
251
252 // Allow user to select characters. Not useful as this selects the ligatures.
253 // _ligatures_label_common.set_selectable( true );
254 // _ligatures_label_discretionary.set_selectable( true );
255 // _ligatures_label_historical.set_selectable( true );
256 // _ligatures_label_contextual.set_selectable( true );
257
258 // Add to frame
259 _ligatures_grid.attach( _ligatures_common, 0, 0, 1, 1);
260 _ligatures_grid.attach( _ligatures_discretionary, 0, 1, 1, 1);
261 _ligatures_grid.attach( _ligatures_historical, 0, 2, 1, 1);
262 _ligatures_grid.attach( _ligatures_contextual, 0, 3, 1, 1);
263 _ligatures_grid.attach( _ligatures_label_common, 1, 0, 1, 1);
265 _ligatures_grid.attach( _ligatures_label_historical, 1, 2, 1, 1);
266 _ligatures_grid.attach( _ligatures_label_contextual, 1, 3, 1, 1);
267
268 _ligatures_grid.set_margin_start(15);
269 _ligatures_grid.set_margin_end(15);
270
273
275
276 // Position ----------------------------------
277
278 // Add tooltips
279 _position_normal.set_tooltip_text( _("Normal position."));
280 _position_sub.set_tooltip_text( _("Subscript. OpenType table: 'subs'") );
281 _position_super.set_tooltip_text( _("Superscript. OpenType table: 'sups'") );
282
283 // Group buttons
284 auto &position_group = _position_normal;
285 _position_sub.set_group(position_group);
286 _position_super.set_group(position_group);
287
288 // Add signals
289 _position_normal.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) );
290 _position_sub.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) );
291 _position_super.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) );
292
293 // Add to frame
294 _position_grid.attach( _position_normal, 0, 0, 1, 1);
295 _position_grid.attach( _position_sub, 1, 0, 1, 1);
296 _position_grid.attach( _position_super, 2, 0, 1, 1);
297
298 _position_grid.set_margin_start(15);
299 _position_grid.set_margin_end(15);
300
301 _position_frame.set_child( _position_grid );
303
305
306 // Caps ----------------------------------
307
308 // Add tooltips
309 _caps_normal.set_tooltip_text( _("Normal capitalization."));
310 _caps_small.set_tooltip_text( _("Small-caps (lowercase). OpenType table: 'smcp'"));
311 _caps_all_small.set_tooltip_text( _("All small-caps (uppercase and lowercase). OpenType tables: 'c2sc' and 'smcp'"));
312 _caps_petite.set_tooltip_text( _("Petite-caps (lowercase). OpenType table: 'pcap'"));
313 _caps_all_petite.set_tooltip_text( _("All petite-caps (uppercase and lowercase). OpenType tables: 'c2sc' and 'pcap'"));
314 _caps_unicase.set_tooltip_text( _("Unicase (small caps for uppercase, normal for lowercase). OpenType table: 'unic'"));
315 _caps_titling.set_tooltip_text( _("Titling caps (lighter-weight uppercase for use in titles). OpenType table: 'titl'"));
316
317 // Group buttons
318 auto &caps_group = _caps_normal;
319 _caps_small.set_group(caps_group);
320 _caps_all_small.set_group(caps_group);
321 _caps_petite.set_group(caps_group);
322 _caps_all_petite.set_group(caps_group);
323 _caps_unicase.set_group(caps_group);
324 _caps_titling.set_group(caps_group);
325
326 // Add signals
327 _caps_normal.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
328 _caps_small.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
329 _caps_all_small.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
330 _caps_petite.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
331 _caps_all_petite.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
332 _caps_unicase.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
333 _caps_titling.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) );
334
335 // Add to frame
336 _caps_grid.attach( _caps_normal, 0, 0, 1, 1);
337 _caps_grid.attach( _caps_unicase, 1, 0, 1, 1);
338 _caps_grid.attach( _caps_titling, 2, 0, 1, 1);
339 _caps_grid.attach( _caps_small, 0, 1, 1, 1);
340 _caps_grid.attach( _caps_all_small, 1, 1, 1, 1);
341 _caps_grid.attach( _caps_petite, 2, 1, 1, 1);
342 _caps_grid.attach( _caps_all_petite, 3, 1, 1, 1);
343
344 _caps_grid.set_margin_start(15);
345 _caps_grid.set_margin_end(15);
346
347 _caps_frame.set_child( _caps_grid );
349
350 caps_init();
351
352 // Numeric ------------------------------
353
354 // Add tooltips
355 _numeric_default_style.set_tooltip_text( _("Normal style."));
356 _numeric_lining.set_tooltip_text( _("Lining numerals. OpenType table: 'lnum'"));
357 _numeric_old_style.set_tooltip_text( _("Old style numerals. OpenType table: 'onum'"));
358 _numeric_default_width.set_tooltip_text( _("Normal widths."));
359 _numeric_proportional.set_tooltip_text( _("Proportional width numerals. OpenType table: 'pnum'"));
360 _numeric_tabular.set_tooltip_text( _("Same width numerals. OpenType table: 'tnum'"));
361 _numeric_default_fractions.set_tooltip_text( _("Normal fractions."));
362 _numeric_diagonal.set_tooltip_text( _("Diagonal fractions. OpenType table: 'frac'"));
363 _numeric_stacked.set_tooltip_text( _("Stacked fractions. OpenType table: 'afrc'"));
364 _numeric_ordinal.set_tooltip_text( _("Ordinals (raised 'th', etc.). OpenType table: 'ordn'"));
365 _numeric_slashed_zero.set_tooltip_text( _("Slashed zeros. OpenType table: 'zero'"));
366
367 // Group buttons
368 auto &style_group = _numeric_default_style;
369 _numeric_lining.set_group(style_group);
370 _numeric_old_style.set_group(style_group);
371
372 auto &width_group = _numeric_default_width;
373 _numeric_proportional.set_group(width_group);
374 _numeric_tabular.set_group(width_group);
375
376 auto &fraction_group = _numeric_default_fractions;
377 _numeric_diagonal.set_group(fraction_group);
378 _numeric_stacked.set_group(fraction_group);
379
380 // Add signals
381 _numeric_default_style.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
382 _numeric_lining.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
383 _numeric_old_style.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
384 _numeric_default_width.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
385 _numeric_proportional.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
386 _numeric_tabular.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
387 _numeric_default_fractions.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
388 _numeric_diagonal.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
389 _numeric_stacked.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
390 _numeric_ordinal.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
391 _numeric_slashed_zero.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) );
392
393 // Add to frame
394 _numeric_grid.attach (_numeric_default_style, 0, 0, 1, 1);
395 _numeric_grid.attach (_numeric_lining, 1, 0, 1, 1);
396 _numeric_grid.attach (_numeric_lining_label, 2, 0, 1, 1);
397 _numeric_grid.attach (_numeric_old_style, 3, 0, 1, 1);
398 _numeric_grid.attach (_numeric_old_style_label, 4, 0, 1, 1);
399
400 _numeric_grid.attach (_numeric_default_width, 0, 1, 1, 1);
401 _numeric_grid.attach (_numeric_proportional, 1, 1, 1, 1);
402 _numeric_grid.attach (_numeric_proportional_label, 2, 1, 1, 1);
403 _numeric_grid.attach (_numeric_tabular, 3, 1, 1, 1);
404 _numeric_grid.attach (_numeric_tabular_label, 4, 1, 1, 1);
405
406 _numeric_grid.attach (_numeric_default_fractions, 0, 2, 1, 1);
407 _numeric_grid.attach (_numeric_diagonal, 1, 2, 1, 1);
408 _numeric_grid.attach (_numeric_diagonal_label, 2, 2, 1, 1);
409 _numeric_grid.attach (_numeric_stacked, 3, 2, 1, 1);
410 _numeric_grid.attach (_numeric_stacked_label, 4, 2, 1, 1);
411
412 _numeric_grid.attach (_numeric_ordinal, 0, 3, 1, 1);
413 _numeric_grid.attach (_numeric_ordinal_label, 1, 3, 4, 1);
414
415 _numeric_grid.attach (_numeric_slashed_zero, 0, 4, 1, 1);
416 _numeric_grid.attach (_numeric_slashed_zero_label, 1, 4, 1, 1);
417
418 _numeric_grid.set_margin_start(15);
419 _numeric_grid.set_margin_end(15);
420
421 _numeric_frame.set_child( _numeric_grid );
423
424 // East Asian
425
426 // Add tooltips
427 _asian_default_variant.set_tooltip_text ( _("Default variant."));
428 _asian_jis78.set_tooltip_text( _("JIS78 forms. OpenType table: 'jp78'."));
429 _asian_jis83.set_tooltip_text( _("JIS83 forms. OpenType table: 'jp83'."));
430 _asian_jis90.set_tooltip_text( _("JIS90 forms. OpenType table: 'jp90'."));
431 _asian_jis04.set_tooltip_text( _("JIS2004 forms. OpenType table: 'jp04'."));
432 _asian_simplified.set_tooltip_text( _("Simplified forms. OpenType table: 'smpl'."));
433 _asian_traditional.set_tooltip_text( _("Traditional forms. OpenType table: 'trad'."));
434 _asian_default_width.set_tooltip_text ( _("Default width."));
435 _asian_full_width.set_tooltip_text( _("Full width variants. OpenType table: 'fwid'."));
436 _asian_proportional_width.set_tooltip_text(_("Proportional width variants. OpenType table: 'pwid'."));
437 _asian_ruby.set_tooltip_text( _("Ruby variants. OpenType table: 'ruby'."));
438
439 // Add signals
440 _asian_default_variant.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
441 _asian_jis78.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
442 _asian_jis83.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
443 _asian_jis90.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
444 _asian_jis04.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
445 _asian_simplified.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
446 _asian_traditional.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
447 _asian_default_width.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
448 _asian_full_width.signal_toggled().connect ( sigc::mem_fun(*this, &FontVariants::asian_callback) );
449 _asian_proportional_width.signal_toggled().connect (sigc::mem_fun(*this, &FontVariants::asian_callback) );
450 _asian_ruby.signal_toggled().connect( sigc::mem_fun(*this, &FontVariants::asian_callback) );
451
452 // Add to frame
453 _asian_grid.attach (_asian_default_variant, 0, 0, 1, 1);
454 _asian_grid.attach (_asian_jis78, 1, 0, 1, 1);
455 _asian_grid.attach (_asian_jis83, 2, 0, 1, 1);
456 _asian_grid.attach (_asian_jis90, 1, 1, 1, 1);
457 _asian_grid.attach (_asian_jis04, 2, 1, 1, 1);
458 _asian_grid.attach (_asian_simplified, 1, 2, 1, 1);
459 _asian_grid.attach (_asian_traditional, 2, 2, 1, 1);
460 _asian_grid.attach (_asian_default_width, 0, 3, 1, 1);
461 _asian_grid.attach (_asian_full_width, 1, 3, 1, 1);
462 _asian_grid.attach (_asian_proportional_width, 2, 3, 1, 1);
463 _asian_grid.attach (_asian_ruby, 0, 4, 1, 1);
464
465 _asian_grid.set_margin_start(15);
466 _asian_grid.set_margin_end(15);
467
468 _asian_frame.set_child( _asian_grid );
470
471 // Group Buttons
472 auto &asian_variant_group = _asian_default_variant;
473 _asian_jis78.set_group(asian_variant_group);
474 _asian_jis83.set_group(asian_variant_group);
475 _asian_jis90.set_group(asian_variant_group);
476 _asian_jis04.set_group(asian_variant_group);
477 _asian_simplified.set_group(asian_variant_group);
478 _asian_traditional.set_group(asian_variant_group);
479
480 auto &asian_width_group = _asian_default_width;
481 _asian_full_width.set_group (asian_width_group);
482 _asian_proportional_width.set_group (asian_width_group);
483
484 // Feature settings ---------------------
485
486 // Add tooltips
487 _feature_entry.set_tooltip_text( _("Feature settings in CSS form (e.g. \"wxyz\" or \"wxyz\" 3)."));
488
489 _feature_substitutions.set_justify( Gtk::Justification::LEFT );
490 _feature_substitutions.set_wrap( true );
491 _feature_substitutions.set_wrap_mode( Pango::WrapMode::WORD_CHAR );
492
493 _feature_list.set_justify( Gtk::Justification::LEFT );
494 _feature_list.set_wrap( true );
495
496 // Add to frame
502
503 _feature_vbox.set_margin_start(15);
504 _feature_vbox.set_margin_end(15);
505
506 _feature_frame.set_child( _feature_vbox );
508
509 // Add signals
510 _feature_entry.signal_changed().connect( sigc::mem_fun(*this, &FontVariants::feature_callback) );
511}
512
513void
515 // std::cout << "FontVariants::ligatures_init()" << std::endl;
516}
517
518void
520 // std::cout << "FontVariants::ligatures_callback()" << std::endl;
521 _ligatures_changed = true;
522 _changed_signal.emit();
523}
524
525void
527 // std::cout << "FontVariants::position_init()" << std::endl;
528}
529
530void
532 // std::cout << "FontVariants::position_callback()" << std::endl;
533 _position_changed = true;
534 _changed_signal.emit();
535}
536
537void
539 // std::cout << "FontVariants::caps_init()" << std::endl;
540}
541
542void
544 // std::cout << "FontVariants::caps_callback()" << std::endl;
545 _caps_changed = true;
546 _changed_signal.emit();
547}
548
549void
551 // std::cout << "FontVariants::numeric_init()" << std::endl;
552}
553
554void
556 // std::cout << "FontVariants::numeric_callback()" << std::endl;
557 _numeric_changed = true;
558 _changed_signal.emit();
559}
560
561void
563 // std::cout << "FontVariants::asian_init()" << std::endl;
564}
565
566void
568 // std::cout << "FontVariants::asian_callback()" << std::endl;
569 _asian_changed = true;
570 _changed_signal.emit();
571}
572
573void
575 // std::cout << "FontVariants::feature_init()" << std::endl;
576}
577
578void
580 // std::cout << "FontVariants::feature_callback()" << std::endl;
581 _feature_changed = true;
582 _changed_signal.emit();
583}
584
585// Update GUI based on query.
586void
587FontVariants::update( SPStyle const *query, bool different_features, Glib::ustring& font_spec ) {
588
589 update_opentype( font_spec );
590
591 _ligatures_all = query->font_variant_ligatures.computed;
593
598
603
604 _position_all = query->font_variant_position.computed;
606
610
614
615 _caps_all = query->font_variant_caps.computed;
616 _caps_mix = query->font_variant_caps.value;
617
625
633
634 _numeric_all = query->font_variant_numeric.computed;
635 _numeric_mix = query->font_variant_numeric.value;
636
638 _numeric_lining.set_active();
640 _numeric_old_style.set_active();
641 } else {
642 _numeric_default_style.set_active();
643 }
644
646 _numeric_proportional.set_active();
648 _numeric_tabular.set_active();
649 } else {
650 _numeric_default_width.set_active();
651 }
652
654 _numeric_diagonal.set_active();
656 _numeric_stacked.set_active();
657 } else {
658 _numeric_default_fractions.set_active();
659 }
660
663
664
673
674 _asian_all = query->font_variant_east_asian.computed;
675 _asian_mix = query->font_variant_east_asian.value;
676
678 _asian_jis78.set_active();
680 _asian_jis83.set_active();
682 _asian_jis90.set_active();
684 _asian_jis04.set_active();
686 _asian_simplified.set_active();
688 _asian_traditional.set_active();
689 } else {
690 _asian_default_variant.set_active();
691 }
692
694 _asian_full_width.set_active();
696 _asian_proportional_width.set_active();
697 } else {
698 _asian_default_width.set_active();
699 }
700
702
712
713 // Fix me: Should match a space if second part matches. ---,
714 // : Add boundary to 'on' and 'off'. v
715 Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("\"(\\w{4})\"\\s*([0-9]+|on|off|)");
716 Glib::MatchInfo matchInfo;
717 std::string setting;
718
719 // Set feature radiobutton (if it exists) or add to _feature_entry string.
720 if (auto const &val = query->font_feature_settings.value()) {
721 for (auto const &token: Glib::Regex::split_simple("\\s*,\\s*", val)) {
722 regex->match(token, matchInfo);
723 if (matchInfo.matches()) {
724 Glib::ustring table = matchInfo.fetch(1);
725
726 if (_features.find(table) != _features.end()) {
727 Glib::ustring value = matchInfo.fetch(2);
728
729 int v = 0;
730 if (value == "0" || value == "off") v = 0;
731 else if (value == "1" || value == "on" || value.empty() ) v = 1;
732 else v = std::stoi(value);
733
734 _features[table]->set_active(v);
735 } else {
736 setting += token + ", ";
737 }
738 }
739 }
740 }
741
742 // Remove final ", "
743 if (setting.length() > 1) {
744 setting.pop_back();
745 setting.pop_back();
746 }
747
748 // Tables without radiobuttons.
749 _feature_entry.set_text( setting );
750
751 if( different_features ) {
752 _feature_label.set_visible(true);
753 } else {
754 _feature_label.set_visible(false);
755 }
756}
757
758// Update GUI based on OpenType tables of selected font (which may be changed in font selector tab).
759void
760FontVariants::update_opentype (Glib::ustring& font_spec) {
761
762 // Disable/Enable based on available OpenType tables.
763 auto res = FontFactory::get().FaceFromFontSpecification(font_spec.c_str());
764 if (res) {
765
766 auto const &tab = res->get_opentype_tables();
767 std::remove_reference<decltype(tab)>::type::const_iterator it;
768
769 if((it = tab.find("liga"))!= tab.end() ||
770 (it = tab.find("clig"))!= tab.end()) {
771 _ligatures_common.set_sensitive();
772 } else {
773 _ligatures_common.set_sensitive( false );
774 }
775
776 if((it = tab.find("dlig"))!= tab.end()) {
777 _ligatures_discretionary.set_sensitive();
778 } else {
779 _ligatures_discretionary.set_sensitive( false );
780 }
781
782 if((it = tab.find("hlig"))!= tab.end()) {
783 _ligatures_historical.set_sensitive();
784 } else {
785 _ligatures_historical.set_sensitive( false );
786 }
787
788 if((it = tab.find("calt"))!= tab.end()) {
789 _ligatures_contextual.set_sensitive();
790 } else {
791 _ligatures_contextual.set_sensitive( false );
792 }
793
794 if((it = tab.find("subs"))!= tab.end()) {
795 _position_sub.set_sensitive();
796 } else {
797 _position_sub.set_sensitive( false );
798 }
799
800 if((it = tab.find("sups"))!= tab.end()) {
801 _position_super.set_sensitive();
802 } else {
803 _position_super.set_sensitive( false );
804 }
805
806 if((it = tab.find("smcp"))!= tab.end()) {
807 _caps_small.set_sensitive();
808 } else {
809 _caps_small.set_sensitive( false );
810 }
811
812 if((it = tab.find("c2sc"))!= tab.end() &&
813 (it = tab.find("smcp"))!= tab.end()) {
814 _caps_all_small.set_sensitive();
815 } else {
816 _caps_all_small.set_sensitive( false );
817 }
818
819 if((it = tab.find("pcap"))!= tab.end()) {
820 _caps_petite.set_sensitive();
821 } else {
822 _caps_petite.set_sensitive( false );
823 }
824
825 if((it = tab.find("c2sc"))!= tab.end() &&
826 (it = tab.find("pcap"))!= tab.end()) {
827 _caps_all_petite.set_sensitive();
828 } else {
829 _caps_all_petite.set_sensitive( false );
830 }
831
832 if((it = tab.find("unic"))!= tab.end()) {
833 _caps_unicase.set_sensitive();
834 } else {
835 _caps_unicase.set_sensitive( false );
836 }
837
838 if((it = tab.find("titl"))!= tab.end()) {
839 _caps_titling.set_sensitive();
840 } else {
841 _caps_titling.set_sensitive( false );
842 }
843
844 if((it = tab.find("lnum"))!= tab.end()) {
845 _numeric_lining.set_sensitive();
846 } else {
847 _numeric_lining.set_sensitive( false );
848 }
849
850 if((it = tab.find("onum"))!= tab.end()) {
851 _numeric_old_style.set_sensitive();
852 } else {
853 _numeric_old_style.set_sensitive( false );
854 }
855
856 if((it = tab.find("pnum"))!= tab.end()) {
857 _numeric_proportional.set_sensitive();
858 } else {
859 _numeric_proportional.set_sensitive( false );
860 }
861
862 if((it = tab.find("tnum"))!= tab.end()) {
863 _numeric_tabular.set_sensitive();
864 } else {
865 _numeric_tabular.set_sensitive( false );
866 }
867
868 if((it = tab.find("frac"))!= tab.end()) {
869 _numeric_diagonal.set_sensitive();
870 } else {
871 _numeric_diagonal.set_sensitive( false );
872 }
873
874 if((it = tab.find("afrac"))!= tab.end()) {
875 _numeric_stacked.set_sensitive();
876 } else {
877 _numeric_stacked.set_sensitive( false );
878 }
879
880 if((it = tab.find("ordn"))!= tab.end()) {
881 _numeric_ordinal.set_sensitive();
882 } else {
883 _numeric_ordinal.set_sensitive( false );
884 }
885
886 if((it = tab.find("zero"))!= tab.end()) {
887 _numeric_slashed_zero.set_sensitive();
888 } else {
889 _numeric_slashed_zero.set_sensitive( false );
890 }
891
892 // East-Asian
893 if((it = tab.find("jp78"))!= tab.end()) {
894 _asian_jis78.set_sensitive();
895 } else {
896 _asian_jis78.set_sensitive( false );
897 }
898
899 if((it = tab.find("jp83"))!= tab.end()) {
900 _asian_jis83.set_sensitive();
901 } else {
902 _asian_jis83.set_sensitive( false );
903 }
904
905 if((it = tab.find("jp90"))!= tab.end()) {
906 _asian_jis90.set_sensitive();
907 } else {
908 _asian_jis90.set_sensitive( false );
909 }
910
911 if((it = tab.find("jp04"))!= tab.end()) {
912 _asian_jis04.set_sensitive();
913 } else {
914 _asian_jis04.set_sensitive( false );
915 }
916
917 if((it = tab.find("smpl"))!= tab.end()) {
918 _asian_simplified.set_sensitive();
919 } else {
920 _asian_simplified.set_sensitive( false );
921 }
922
923 if((it = tab.find("trad"))!= tab.end()) {
924 _asian_traditional.set_sensitive();
925 } else {
926 _asian_traditional.set_sensitive( false );
927 }
928
929 if((it = tab.find("fwid"))!= tab.end()) {
930 _asian_full_width.set_sensitive();
931 } else {
932 _asian_full_width.set_sensitive( false );
933 }
934
935 if((it = tab.find("pwid"))!= tab.end()) {
936 _asian_proportional_width.set_sensitive();
937 } else {
938 _asian_proportional_width.set_sensitive( false );
939 }
940
941 if((it = tab.find("ruby"))!= tab.end()) {
942 _asian_ruby.set_sensitive();
943 } else {
944 _asian_ruby.set_sensitive( false );
945 }
946
947 // List available ligatures
948 Glib::ustring markup_liga;
949 Glib::ustring markup_dlig;
950 Glib::ustring markup_hlig;
951 Glib::ustring markup_calt;
952
953 for (auto &table : tab) {
954 if (table.first == "liga" ||
955 table.first == "clig" ||
956 table.first == "dlig" ||
957 table.first == "hgli" ||
958 table.first == "calt") {
959
960 Glib::ustring markup;
961 markup += "<span font_family='";
962 markup += sp_font_description_get_family(res->get_descr());
963 markup += "'>";
964 markup += Glib::Markup::escape_text(table.second.output);
965 markup += "</span>";
966
967 if (table.first == "liga") markup_liga += markup;
968 if (table.first == "clig") markup_liga += markup;
969 if (table.first == "dlig") markup_dlig += markup;
970 if (table.first == "hlig") markup_hlig += markup;
971 if (table.first == "calt") markup_calt += markup;
972 }
973 }
974
975 _ligatures_label_common.set_markup ( markup_liga.c_str() );
976 _ligatures_label_discretionary.set_markup ( markup_dlig.c_str() );
977 _ligatures_label_historical.set_markup ( markup_hlig.c_str() );
978 _ligatures_label_contextual.set_markup ( markup_calt.c_str() );
979
980 // List available numeric variants
981 Glib::ustring markup_lnum;
982 Glib::ustring markup_onum;
983 Glib::ustring markup_pnum;
984 Glib::ustring markup_tnum;
985 Glib::ustring markup_frac;
986 Glib::ustring markup_afrc;
987 Glib::ustring markup_ordn;
988 Glib::ustring markup_zero;
989
990 for (auto &table : res->get_opentype_tables()) {
991 Glib::ustring markup;
992 markup += "<span font_family='";
993 markup += sp_font_description_get_family(res->get_descr());
994 markup += "' font_features='";
995 markup += table.first;
996 markup += "'>";
997 if (table.first == "lnum" ||
998 table.first == "onum" ||
999 table.first == "pnum" ||
1000 table.first == "tnum") markup += "0123456789";
1001 if (table.first == "zero") markup += "0";
1002 if (table.first == "ordn") markup += "[" + table.second.before + "]" + table.second.output;
1003 if (table.first == "frac" ||
1004 table.first == "afrc" ) markup += "1/2 2/3 3/4 4/5 5/6"; // Can we do better?
1005 markup += "</span>";
1006
1007 if (table.first == "lnum") markup_lnum += markup;
1008 if (table.first == "onum") markup_onum += markup;
1009 if (table.first == "pnum") markup_pnum += markup;
1010 if (table.first == "tnum") markup_tnum += markup;
1011 if (table.first == "frac") markup_frac += markup;
1012 if (table.first == "afrc") markup_afrc += markup;
1013 if (table.first == "ordn") markup_ordn += markup;
1014 if (table.first == "zero") markup_zero += markup;
1015 }
1016
1017 _numeric_lining_label.set_markup ( markup_lnum.c_str() );
1018 _numeric_old_style_label.set_markup ( markup_onum.c_str() );
1019 _numeric_proportional_label.set_markup ( markup_pnum.c_str() );
1020 _numeric_tabular_label.set_markup ( markup_tnum.c_str() );
1021 _numeric_diagonal_label.set_markup ( markup_frac.c_str() );
1022 _numeric_stacked_label.set_markup ( markup_afrc.c_str() );
1023 _numeric_ordinal_label.set_markup ( markup_ordn.c_str() );
1024 _numeric_slashed_zero_label.set_markup ( markup_zero.c_str() );
1025
1026 // Make list of tables not handled above.
1027 auto table_copy = res->get_opentype_tables();
1028 if( (it = table_copy.find("liga")) != table_copy.end() ) table_copy.erase( it );
1029 if( (it = table_copy.find("clig")) != table_copy.end() ) table_copy.erase( it );
1030 if( (it = table_copy.find("dlig")) != table_copy.end() ) table_copy.erase( it );
1031 if( (it = table_copy.find("hlig")) != table_copy.end() ) table_copy.erase( it );
1032 if( (it = table_copy.find("calt")) != table_copy.end() ) table_copy.erase( it );
1033
1034 if( (it = table_copy.find("subs")) != table_copy.end() ) table_copy.erase( it );
1035 if( (it = table_copy.find("sups")) != table_copy.end() ) table_copy.erase( it );
1036
1037 if( (it = table_copy.find("smcp")) != table_copy.end() ) table_copy.erase( it );
1038 if( (it = table_copy.find("c2sc")) != table_copy.end() ) table_copy.erase( it );
1039 if( (it = table_copy.find("pcap")) != table_copy.end() ) table_copy.erase( it );
1040 if( (it = table_copy.find("c2pc")) != table_copy.end() ) table_copy.erase( it );
1041 if( (it = table_copy.find("unic")) != table_copy.end() ) table_copy.erase( it );
1042 if( (it = table_copy.find("titl")) != table_copy.end() ) table_copy.erase( it );
1043
1044 if( (it = table_copy.find("lnum")) != table_copy.end() ) table_copy.erase( it );
1045 if( (it = table_copy.find("onum")) != table_copy.end() ) table_copy.erase( it );
1046 if( (it = table_copy.find("pnum")) != table_copy.end() ) table_copy.erase( it );
1047 if( (it = table_copy.find("tnum")) != table_copy.end() ) table_copy.erase( it );
1048 if( (it = table_copy.find("frac")) != table_copy.end() ) table_copy.erase( it );
1049 if( (it = table_copy.find("afrc")) != table_copy.end() ) table_copy.erase( it );
1050 if( (it = table_copy.find("ordn")) != table_copy.end() ) table_copy.erase( it );
1051 if( (it = table_copy.find("zero")) != table_copy.end() ) table_copy.erase( it );
1052
1053 if( (it = table_copy.find("jp78")) != table_copy.end() ) table_copy.erase( it );
1054 if( (it = table_copy.find("jp83")) != table_copy.end() ) table_copy.erase( it );
1055 if( (it = table_copy.find("jp90")) != table_copy.end() ) table_copy.erase( it );
1056 if( (it = table_copy.find("jp04")) != table_copy.end() ) table_copy.erase( it );
1057 if( (it = table_copy.find("smpl")) != table_copy.end() ) table_copy.erase( it );
1058 if( (it = table_copy.find("trad")) != table_copy.end() ) table_copy.erase( it );
1059 if( (it = table_copy.find("fwid")) != table_copy.end() ) table_copy.erase( it );
1060 if( (it = table_copy.find("pwid")) != table_copy.end() ) table_copy.erase( it );
1061 if( (it = table_copy.find("ruby")) != table_copy.end() ) table_copy.erase( it );
1062
1063 // An incomplete list of tables that should not be exposed to the user:
1064 if( (it = table_copy.find("abvf")) != table_copy.end() ) table_copy.erase( it );
1065 if( (it = table_copy.find("abvs")) != table_copy.end() ) table_copy.erase( it );
1066 if( (it = table_copy.find("akhn")) != table_copy.end() ) table_copy.erase( it );
1067 if( (it = table_copy.find("blwf")) != table_copy.end() ) table_copy.erase( it );
1068 if( (it = table_copy.find("blws")) != table_copy.end() ) table_copy.erase( it );
1069 if( (it = table_copy.find("ccmp")) != table_copy.end() ) table_copy.erase( it );
1070 if( (it = table_copy.find("cjct")) != table_copy.end() ) table_copy.erase( it );
1071 if( (it = table_copy.find("dnom")) != table_copy.end() ) table_copy.erase( it );
1072 if( (it = table_copy.find("dtls")) != table_copy.end() ) table_copy.erase( it );
1073 if( (it = table_copy.find("fina")) != table_copy.end() ) table_copy.erase( it );
1074 if( (it = table_copy.find("half")) != table_copy.end() ) table_copy.erase( it );
1075 if( (it = table_copy.find("haln")) != table_copy.end() ) table_copy.erase( it );
1076 if( (it = table_copy.find("init")) != table_copy.end() ) table_copy.erase( it );
1077 if( (it = table_copy.find("isol")) != table_copy.end() ) table_copy.erase( it );
1078 if( (it = table_copy.find("locl")) != table_copy.end() ) table_copy.erase( it );
1079 if( (it = table_copy.find("medi")) != table_copy.end() ) table_copy.erase( it );
1080 if( (it = table_copy.find("nukt")) != table_copy.end() ) table_copy.erase( it );
1081 if( (it = table_copy.find("numr")) != table_copy.end() ) table_copy.erase( it );
1082 if( (it = table_copy.find("pref")) != table_copy.end() ) table_copy.erase( it );
1083 if( (it = table_copy.find("pres")) != table_copy.end() ) table_copy.erase( it );
1084 if( (it = table_copy.find("pstf")) != table_copy.end() ) table_copy.erase( it );
1085 if( (it = table_copy.find("psts")) != table_copy.end() ) table_copy.erase( it );
1086 if( (it = table_copy.find("rlig")) != table_copy.end() ) table_copy.erase( it );
1087 if( (it = table_copy.find("rkrf")) != table_copy.end() ) table_copy.erase( it );
1088 if( (it = table_copy.find("rphf")) != table_copy.end() ) table_copy.erase( it );
1089 if( (it = table_copy.find("rtlm")) != table_copy.end() ) table_copy.erase( it );
1090 if( (it = table_copy.find("ssty")) != table_copy.end() ) table_copy.erase( it );
1091 if( (it = table_copy.find("vatu")) != table_copy.end() ) table_copy.erase( it );
1092
1093 // Clear out old features
1095 _features.clear();
1096
1097 std::string markup;
1098 int grid_row = 0;
1099
1100 // GSUB lookup type 1 (1 to 1 mapping).
1101 for (auto &table: res->get_opentype_tables()) {
1102 if (table.first == "case" ||
1103 table.first == "hist" ||
1104 (table.first[0] == 's' && table.first[1] == 's' && !(table.first[2] == 't'))) {
1105
1106 if( (it = table_copy.find(table.first)) != table_copy.end() ) table_copy.erase( it );
1107
1108 _features[table.first] = new Feature (table.first, table.second, 2,
1109 sp_font_description_get_family(res->get_descr()),
1110 _feature_grid, grid_row, this);
1111 grid_row++;
1112 }
1113 }
1114
1115 // GSUB lookup type 3 (1 to many mapping). Optionally type 1.
1116 for (auto &table : res->get_opentype_tables()) {
1117 if (table.first == "salt" ||
1118 table.first == "swsh" ||
1119 table.first == "cwsh" ||
1120 table.first == "ornm" ||
1121 table.first == "nalt" ||
1122 (table.first[0] == 'c' && table.first[1] == 'v')) {
1123
1124 if (table.second.input.length() == 0) {
1125 // This can happen if a table is not in the 'DFLT' script and 'dflt' language.
1126 // We should be using the 'lang' attribute to find the correct tables.
1127 // std::cerr << "FontVariants::open_type_update: "
1128 // << table.first << " has no entries!" << std::endl;
1129 continue;
1130 }
1131
1132 if( (it = table_copy.find(table.first)) != table_copy.end() ) table_copy.erase( it );
1133
1134 // Our lame attempt at determining number of alternative glyphs for one glyph:
1135 int number = table.second.output.length() / table.second.input.length();
1136 if (number < 1) {
1137 number = 1; // Must have at least on/off, see comment above about 'lang' attribute.
1138 // std::cout << table.first << " "
1139 // << table.second.output.length() << "/"
1140 // << table.second.input.length() << "="
1141 // << number << std::endl;
1142 }
1143
1144 _features[table.first] = new Feature (table.first, table.second, number+1,
1145 sp_font_description_get_family(res->get_descr()),
1146 _feature_grid, grid_row, this);
1147 grid_row++;
1148 }
1149 }
1150
1151 _feature_substitutions.set_markup ( markup.c_str() );
1152
1153 std::string ott_list = "OpenType tables not included above: ";
1154 for(it = table_copy.begin(); it != table_copy.end(); ++it) {
1155 ott_list += it->first;
1156 ott_list += ", ";
1157 }
1158
1159 if (table_copy.size() > 0) {
1160 ott_list.pop_back();
1161 ott_list.pop_back();
1162 _feature_list.set_text( ott_list.c_str() );
1163 } else {
1164 _feature_list.set_text( "" );
1165 }
1166
1167 } else {
1168 std::cerr << "FontVariants::update(): Couldn't find FontInstance for: "
1169 << font_spec.raw() << std::endl;
1170 }
1171
1172 _ligatures_changed = false;
1173 _position_changed = false;
1174 _caps_changed = false;
1175 _numeric_changed = false;
1176 _feature_changed = false;
1177}
1178
1179void
1181
1182 // Ligatures
1183 bool common = _ligatures_common.get_active();
1184 bool discretionary = _ligatures_discretionary.get_active();
1185 bool historical = _ligatures_historical.get_active();
1186 bool contextual = _ligatures_contextual.get_active();
1187
1188 if( !common && !discretionary && !historical && !contextual ) {
1189 sp_repr_css_set_property(css, "font-variant-ligatures", "none" );
1190 } else if ( common && !discretionary && !historical && contextual ) {
1191 sp_repr_css_set_property(css, "font-variant-ligatures", "normal" );
1192 } else {
1193 Glib::ustring css_string;
1194 if ( !common )
1195 css_string += "no-common-ligatures ";
1196 if ( discretionary )
1197 css_string += "discretionary-ligatures ";
1198 if ( historical )
1199 css_string += "historical-ligatures ";
1200 if ( !contextual )
1201 css_string += "no-contextual ";
1202 sp_repr_css_set_property(css, "font-variant-ligatures", css_string.c_str() );
1203 }
1204
1205 // Position
1206 {
1207 unsigned position_new = SP_CSS_FONT_VARIANT_POSITION_NORMAL;
1208 Glib::ustring css_string;
1209 if( _position_normal.get_active() ) {
1210 css_string = "normal";
1211 } else if( _position_sub.get_active() ) {
1212 css_string = "sub";
1213 position_new = SP_CSS_FONT_VARIANT_POSITION_SUB;
1214 } else if( _position_super.get_active() ) {
1215 css_string = "super";
1217 }
1218
1219 // 'if' may not be necessary... need to test.
1220 if( (_position_all != position_new) || ((_position_mix != 0) && _position_changed) ) {
1221 sp_repr_css_set_property(css, "font-variant-position", css_string.c_str() );
1222 }
1223 }
1224
1225 // Caps
1226 {
1227 //unsigned caps_new;
1228 Glib::ustring css_string;
1229 if( _caps_normal.get_active() ) {
1230 css_string = "normal";
1231 // caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL;
1232 } else if( _caps_small.get_active() ) {
1233 css_string = "small-caps";
1234 // caps_new = SP_CSS_FONT_VARIANT_CAPS_SMALL;
1235 } else if( _caps_all_small.get_active() ) {
1236 css_string = "all-small-caps";
1237 // caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL;
1238 } else if( _caps_petite.get_active() ) {
1239 css_string = "petite";
1240 // caps_new = SP_CSS_FONT_VARIANT_CAPS_PETITE;
1241 } else if( _caps_all_petite.get_active() ) {
1242 css_string = "all-petite";
1243 // caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE;
1244 } else if( _caps_unicase.get_active() ) {
1245 css_string = "unicase";
1246 // caps_new = SP_CSS_FONT_VARIANT_CAPS_UNICASE;
1247 } else if( _caps_titling.get_active() ) {
1248 css_string = "titling";
1249 // caps_new = SP_CSS_FONT_VARIANT_CAPS_TITLING;
1250 //} else {
1251 // caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL;
1252 }
1253
1254 // May not be necessary... need to test.
1255 //if( (_caps_all != caps_new) || ((_caps_mix != 0) && _caps_changed) ) {
1256 sp_repr_css_set_property(css, "font-variant-caps", css_string.c_str() );
1257 //}
1258 }
1259
1260 // Numeric
1261 bool default_style = _numeric_default_style.get_active();
1262 bool lining = _numeric_lining.get_active();
1263 bool old_style = _numeric_old_style.get_active();
1264
1265 bool default_width = _numeric_default_width.get_active();
1266 bool proportional = _numeric_proportional.get_active();
1267 bool tabular = _numeric_tabular.get_active();
1268
1269 bool default_fractions = _numeric_default_fractions.get_active();
1270 bool diagonal = _numeric_diagonal.get_active();
1271 bool stacked = _numeric_stacked.get_active();
1272
1273 bool ordinal = _numeric_ordinal.get_active();
1274 bool slashed_zero = _numeric_slashed_zero.get_active();
1275
1276 if (default_style & default_width & default_fractions & !ordinal & !slashed_zero) {
1277 sp_repr_css_set_property(css, "font-variant-numeric", "normal");
1278 } else {
1279 Glib::ustring css_string;
1280 if ( lining )
1281 css_string += "lining-nums ";
1282 if ( old_style )
1283 css_string += "oldstyle-nums ";
1284 if ( proportional )
1285 css_string += "proportional-nums ";
1286 if ( tabular )
1287 css_string += "tabular-nums ";
1288 if ( diagonal )
1289 css_string += "diagonal-fractions ";
1290 if ( stacked )
1291 css_string += "stacked-fractions ";
1292 if ( ordinal )
1293 css_string += "ordinal ";
1294 if ( slashed_zero )
1295 css_string += "slashed-zero ";
1296 sp_repr_css_set_property(css, "font-variant-numeric", css_string.c_str() );
1297 }
1298
1299 // East Asian
1300 bool jis78 = _asian_jis78.get_active();
1301 bool jis83 = _asian_jis83.get_active();
1302 bool jis90 = _asian_jis90.get_active();
1303 bool jis04 = _asian_jis04.get_active();
1304 bool simplified = _asian_simplified.get_active();
1305 bool traditional = _asian_traditional.get_active();
1306 bool asian_width = _asian_default_width.get_active();
1307 bool fwid = _asian_full_width.get_active();
1308 bool pwid = _asian_proportional_width.get_active();
1309 bool ruby = _asian_ruby.get_active();
1310
1311 if (default_style & asian_width & !ruby) {
1312 sp_repr_css_set_property(css, "font-variant-east-asian", "normal");
1313 } else {
1314 Glib::ustring css_string;
1315 if (jis78) css_string += "jis78 ";
1316 if (jis83) css_string += "jis83 ";
1317 if (jis90) css_string += "jis90 ";
1318 if (jis04) css_string += "jis04 ";
1319 if (simplified) css_string += "simplfied ";
1320 if (traditional) css_string += "traditional ";
1321
1322 if (fwid) css_string += "fwid ";
1323 if (pwid) css_string += "pwid ";
1324
1325 if (ruby) css_string += "ruby ";
1326
1327 sp_repr_css_set_property(css, "font-variant-east-asian", css_string.c_str() );
1328 }
1329
1330 // Feature settings
1331 Glib::ustring feature_string;
1332 for (auto const &i: _features) {
1333 feature_string += i.second->get_css();
1334 }
1335
1336 feature_string += _feature_entry.get_text();
1337 // std::cout << "feature_string: " << feature_string << std::endl;
1338
1339 if (!feature_string.empty()) {
1340 sp_repr_css_set_property(css, "font-feature-settings", feature_string.c_str());
1341 } else {
1342 sp_repr_css_unset_property(css, "font-feature-settings");
1343 }
1344}
1345
1346Glib::ustring
1348
1349 Glib::ustring markup;
1350
1351 // Ligatures
1352 bool common = _ligatures_common.get_active();
1353 bool discretionary = _ligatures_discretionary.get_active();
1354 bool historical = _ligatures_historical.get_active();
1355 bool contextual = _ligatures_contextual.get_active();
1356
1357 if (!common) markup += "liga=0,clig=0,"; // On by default.
1358 if (discretionary) markup += "dlig=1,";
1359 if (historical) markup += "hlig=1,";
1360 if (contextual) markup += "calt=1,";
1361
1362 // Position
1363 if ( _position_sub.get_active() ) markup += "subs=1,";
1364 else if ( _position_super.get_active() ) markup += "sups=1,";
1365
1366 // Caps
1367 if ( _caps_small.get_active() ) markup += "smcp=1,";
1368 else if ( _caps_all_small.get_active() ) markup += "c2sc=1,smcp=1,";
1369 else if ( _caps_petite.get_active() ) markup += "pcap=1,";
1370 else if ( _caps_all_petite.get_active() ) markup += "c2pc=1,pcap=1,";
1371 else if ( _caps_unicase.get_active() ) markup += "unic=1,";
1372 else if ( _caps_titling.get_active() ) markup += "titl=1,";
1373
1374 // Numeric
1375 bool lining = _numeric_lining.get_active();
1376 bool old_style = _numeric_old_style.get_active();
1377
1378 bool proportional = _numeric_proportional.get_active();
1379 bool tabular = _numeric_tabular.get_active();
1380
1381 bool diagonal = _numeric_diagonal.get_active();
1382 bool stacked = _numeric_stacked.get_active();
1383
1384 bool ordinal = _numeric_ordinal.get_active();
1385 bool slashed_zero = _numeric_slashed_zero.get_active();
1386
1387 if (lining) markup += "lnum=1,";
1388 if (old_style) markup += "onum=1,";
1389 if (proportional) markup += "pnum=1,";
1390 if (tabular) markup += "tnum=1,";
1391 if (diagonal) markup += "frac=1,";
1392 if (stacked) markup += "afrc=1,";
1393 if (ordinal) markup += "ordn=1,";
1394 if (slashed_zero) markup += "zero=1,";
1395
1396 // East Asian
1397 bool jis78 = _asian_jis78.get_active();
1398 bool jis83 = _asian_jis83.get_active();
1399 bool jis90 = _asian_jis90.get_active();
1400 bool jis04 = _asian_jis04.get_active();
1401 bool simplified = _asian_simplified.get_active();
1402 bool traditional = _asian_traditional.get_active();
1403 //bool asian_width = _asian_default_width.get_active();
1404 bool fwid = _asian_full_width.get_active();
1405 bool pwid = _asian_proportional_width.get_active();
1406 bool ruby = _asian_ruby.get_active();
1407
1408 if (jis78 ) markup += "jp78=1,";
1409 if (jis83 ) markup += "jp83=1,";
1410 if (jis90 ) markup += "jp90=1,";
1411 if (jis04 ) markup += "jp04=1,";
1412 if (simplified ) markup += "smpl=1,";
1413 if (traditional ) markup += "trad=1,";
1414
1415 if (fwid ) markup += "fwid=1,";
1416 if (pwid ) markup += "pwid=1,";
1417
1418 if (ruby ) markup += "ruby=1,";
1419
1420 // Feature settings
1421 Glib::ustring feature_string;
1422 for (auto const &i: _features) {
1423 feature_string += i.second->get_css();
1424 }
1425
1426 feature_string += _feature_entry.get_text();
1427 if (!feature_string.empty()) {
1428 markup += feature_string;
1429 }
1430
1431 // std::cout << "|" << markup << "|" << std::endl;
1432 return markup;
1433}
1434
1435} // namespace Inkscape::UI::Widget
1436
1437/*
1438 Local Variables:
1439 mode:c++
1440 c-file-style:"stroustrup"
1441 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1442 indent-tabs-mode:nil
1443 fill-column:99
1444 End:
1445*/
1446// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
std::shared_ptr< FontInstance > FaceFromFontSpecification(char const *fontSpecification)
void update(SPStyle const *query, bool different_features, Glib::ustring &font_spec)
Update GUI based on query results.
Gtk::CheckButton _numeric_default_fractions
Gtk::CheckButton _ligatures_discretionary
sigc::signal< void()> _changed_signal
void fill_css(SPCSSAttr *css)
Fill SPCSSAttr based on settings of buttons.
Glib::ustring get_markup()
Get CSS string for markup.
std::map< std::string, Feature * > _features
void update_opentype(Glib::ustring &font_spec)
Update GUI based on OpenType features of selected font.
static FontFactory & get(Args &&... args)
Definition statics.h:153
Glib::ustring input
An SVG style object.
Definition style.h:45
T< SPAttr::FONT_VARIANT_EAST_ASIAN, SPIEastAsian > font_variant_east_asian
Font variant East Asian.
Definition style.h:138
T< SPAttr::FONT_FEATURE_SETTINGS, SPIString > font_feature_settings
Font feature settings (Low level access to TrueType tables)
Definition style.h:140
T< SPAttr::FONT_VARIANT_NUMERIC, SPINumeric > font_variant_numeric
Font variant numeric (numerical formatting)
Definition style.h:134
T< SPAttr::FONT_VARIANT_CAPS, SPIEnum< SPCSSFontVariantCaps > > font_variant_caps
Font variant caps (small caps)
Definition style.h:132
T< SPAttr::FONT_VARIANT_POSITION, SPIEnum< SPCSSFontVariantPosition > > font_variant_position
Font variant position (subscript/superscript)
Definition style.h:130
T< SPAttr::FONT_VARIANT_LIGATURES, SPILigatures > font_variant_ligatures
Font variant ligatures.
Definition style.h:128
std::shared_ptr< Css const > css
Editable view implementation.
static char const *const parent
Definition dir-util.cpp:70
char const * sp_font_description_get_family(PangoFontDescription const *fontDescr)
TODO: insert short description here.
The data describing a single loaded font.
Glib::ustring label
Definition desktop.h:50
Custom widgets.
Definition desktop.h:126
void remove_all_children(Widget &widget)
For each child in get_children(widget), call widget.remove(*child). May not cause delete child!
Definition util.h:75
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition pack.cpp:141
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
Set a style property to "inkscape:unset".
Definition repr-css.cpp:201
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
Definition repr-css.cpp:190
@ SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL
@ SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY
@ SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL
@ SP_CSS_FONT_VARIANT_LIGATURES_COMMON
@ SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS
@ SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS
@ SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS
@ SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO
@ SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS
@ SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS
@ SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL
@ SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS
@ SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL
@ SP_CSS_FONT_VARIANT_CAPS_SMALL
@ SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE
@ SP_CSS_FONT_VARIANT_CAPS_NORMAL
@ SP_CSS_FONT_VARIANT_CAPS_UNICASE
@ SP_CSS_FONT_VARIANT_CAPS_TITLING
@ SP_CSS_FONT_VARIANT_CAPS_PETITE
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED
@ SP_CSS_FONT_VARIANT_POSITION_SUB
@ SP_CSS_FONT_VARIANT_POSITION_SUPER
@ SP_CSS_FONT_VARIANT_POSITION_NORMAL
Glib::ustring name
Definition toolbars.cpp:55