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