[ttfautohintGUI] Fix tooltip for control instructions file button.
[ttfautohint.git] / frontend / maingui.cpp
blob6fa625659b57ae776fb9ceaccee4390c99cb4a83
1 // maingui.cpp
3 // Copyright (C) 2012-2017 by Werner Lemberg.
4 //
5 // This file is part of the ttfautohint library, and may only be used,
6 // modified, and distributed under the terms given in `COPYING'. By
7 // continuing to use, modify, or distribute this file you indicate that you
8 // have read `COPYING' and understand and accept it fully.
9 //
10 // The file `COPYING' mentioned in the previous paragraph is distributed
11 // with the ttfautohint library.
14 #include <config.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <locale.h>
21 #include <QtGui>
23 #include <ft2build.h>
24 #include FT_FREETYPE_H
26 #include "info.h"
27 #include "maingui.h"
29 #include <ttfautohint.h>
32 // XXX Qt 4.8 bug: locale->quoteString("foo")
33 // inserts wrongly encoded quote characters
34 // into rich text QString
35 #if HAVE_QT_QUOTESTRING
36 # define QUOTE_STRING(x) locale->quoteString(x)
37 # define QUOTE_STRING_LITERAL(x) locale->quoteString(x)
38 #else
39 # define QUOTE_STRING(x) "\"" + x + "\""
40 # define QUOTE_STRING_LITERAL(x) "\"" x "\""
41 #endif
44 // Shorthand for `tr' using a local `TRDOMAIN'.
45 #define Tr(text) QCoreApplication::translate(TRDOMAIN, text)
48 typedef struct Tag_Names_
50 const char* tag;
51 const char* description;
52 } Tag_Names;
55 // the available script tags and its descriptions are directly extracted
56 // from `ttfautohint-scripts.h'
57 #undef SCRIPT
58 #define SCRIPT(s, S, d, h, H, ss) \
59 {#s, d},
61 const Tag_Names script_names[] =
63 #include <ttfautohint-scripts.h>
64 {NULL, NULL}
68 // the available feature tags and its descriptions are directly extracted
69 // from `ttfautohint-coverages.h'
70 #undef COVERAGE
71 #define COVERAGE(n, N, d, t, t1, t2, t3, t4) \
72 {#t, d},
74 const Tag_Names feature_names[] =
76 #include <ttfautohint-coverages.h>
77 {NULL, NULL}
81 // used hotkeys:
82 // a: Add ttf&autohint Info
83 // b: Add TTFA info ta&ble
84 // c: x Height In&crease Limit / No x Height In&crease
85 // d: &Dehint
86 // e: Control Instructions Fil&e
87 // f: &File (menu)
88 // g: Stron&g Stem Width and Positioning
89 // h: &Help (menu)
90 // i: &Input Font
91 // j: Ad&just Subglyphs
92 // k: Fallbac&k Script
93 // l: Hinting &Limit / No Hinting &Limit
94 // m: Hint Co&mposites
95 // n: Hint Set Range Mi&nimum
96 // o: &Output Font
97 // p: Windows Com&patibility
98 // q: --
99 // r: &Run
100 // s: Fallback &Stem Width / Default Fallback &Stem Width
101 // t: x Height Snapping Excep&tions
102 // u: Defa&ult Script
103 // v: --
104 // w: &Watch Input Files
105 // x: Hint Set Range Ma&ximum
106 // y: S&ymbol Font
107 // z: Blue &Zone Reference Font
108 // :: Family Suffix&:
110 Main_GUI::Main_GUI(bool horizontal_layout,
111 int range_min,
112 int range_max,
113 int limit,
114 bool gray,
115 bool gdi,
116 bool dw,
117 int increase,
118 const char* exceptions,
119 int stem_width,
120 bool ignore,
121 bool wincomp,
122 bool adjust,
123 bool composites,
124 bool no,
125 bool detailed,
126 const char* dflt,
127 const char* fallback,
128 bool scaling,
129 const char* suffix,
130 bool symb,
131 bool dh,
132 bool TTFA)
133 : hinting_range_min(range_min),
134 hinting_range_max(range_max),
135 hinting_limit(limit),
136 gray_strong_stem_width(gray),
137 gdi_cleartype_strong_stem_width(gdi),
138 dw_cleartype_strong_stem_width(dw),
139 increase_x_height(increase),
140 x_height_snapping_exceptions_string(exceptions),
141 fallback_stem_width(stem_width),
142 ignore_restrictions(ignore),
143 windows_compatibility(wincomp),
144 adjust_subglyphs(adjust),
145 hint_composites(composites),
146 no_info(no),
147 detailed_info(detailed),
148 fallback_scaling(scaling),
149 family_suffix(suffix),
150 symbol(symb),
151 dehint(dh),
152 TTFA_info(TTFA),
153 // constants
154 fallback_do_scale(1),
155 fallback_do_hint(0)
157 int i;
159 for (i = 0; script_names[i].tag; i++)
161 if (!strcmp("latn", script_names[i].tag))
162 latn_script_idx = i;
163 if (!strcmp("none", script_names[i].tag))
164 none_script_idx = i;
167 // map default script and fallback script tags to indices
168 for (i = 0; script_names[i].tag; i++)
169 if (!strcmp(dflt, script_names[i].tag))
170 break;
171 default_script_idx = script_names[i].tag ? i : latn_script_idx;
173 for (i = 0; script_names[i].tag; i++)
174 if (!strcmp(fallback, script_names[i].tag))
175 break;
176 fallback_script_idx = script_names[i].tag ? i : none_script_idx;
178 x_height_snapping_exceptions = NULL;
180 // if the current input files have been updated
181 // we wait a given time interval, then we reload the files
182 file_watcher = new QFileSystemWatcher(this);
183 timer = new QTimer(this);
184 timer->setInterval(1000); // XXX make this configurable
185 timer->setSingleShot(true);
186 fileinfo_input_file.setCaching(false);
187 fileinfo_control_file.setCaching(false);
188 fileinfo_reference_file.setCaching(false);
190 // XXX register translations somewhere and loop over them
191 if (QLocale::system().name() == "en_US")
192 locale = new QLocale;
193 else
194 locale = new QLocale(QLocale::C);
196 // For real numbers (both parsing and displaying) we only use `.' as the
197 // decimal separator; similarly, we don't want localized formats like a
198 // thousands separator for any number.
199 setlocale(LC_NUMERIC, "C");
201 create_layout(horizontal_layout);
202 create_connections();
203 create_actions();
204 create_menus();
205 create_status_bar();
207 set_defaults();
208 read_settings();
210 setUnifiedTitleAndToolBarOnMac(true);
214 Main_GUI::~Main_GUI()
216 number_set_free(x_height_snapping_exceptions);
220 // overloading
222 void
223 Main_GUI::closeEvent(QCloseEvent* event)
225 write_settings();
226 event->accept();
230 void
231 Main_GUI::about()
233 QMessageBox::about(this,
234 tr("About TTFautohint"),
235 tr("<p>This is <b>TTFautohint</b> version %1<br>"
236 " Copyright %2 2011-2017<br>"
237 " by Werner Lemberg <tt>&lt;wl@gnu.org&gt;</tt></p>"
239 "<p><b>TTFautohint</b> adds new auto-generated hints"
240 " to a TrueType font or TrueType collection.</p>"
242 "<p>License:"
243 " <a href='http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/FTL.TXT'>FreeType"
244 " License (FTL)</a> or"
245 " <a href='http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/GPLv2.TXT'>GNU"
246 " GPLv2</a></p>")
247 .arg(VERSION)
248 .arg(QChar(0xA9)));
252 void
253 Main_GUI::browse_input()
255 // XXX remember last directory
256 QString file = QFileDialog::getOpenFileName(
257 this,
258 tr("Open Input Font"),
259 QDir::homePath(),
260 "");
262 if (!file.isEmpty())
263 input_line->setText(QDir::toNativeSeparators(file));
267 void
268 Main_GUI::browse_output()
270 // XXX remember last directory
271 QString file = QFileDialog::getSaveFileName(
272 this,
273 tr("Open Output Font"),
274 QDir::homePath(),
275 "");
277 if (!file.isEmpty())
278 output_line->setText(QDir::toNativeSeparators(file));
282 void
283 Main_GUI::browse_control()
285 // XXX remember last directory
286 QString file = QFileDialog::getOpenFileName(
287 this,
288 tr("Open Control Instructions File"),
289 QDir::homePath(),
290 "");
292 if (!file.isEmpty())
293 control_line->setText(QDir::toNativeSeparators(file));
297 void
298 Main_GUI::browse_reference()
300 // XXX remember last directory
301 QString file = QFileDialog::getOpenFileName(
302 this,
303 tr("Open Blue Zone Reference Font"),
304 QDir::homePath(),
305 "");
307 if (!file.isEmpty())
308 reference_line->setText(QDir::toNativeSeparators(file));
312 void
313 Main_GUI::check_min()
315 int min = min_box->value();
316 int max = max_box->value();
317 int limit = limit_box->value();
318 if (min > max)
319 max_box->setValue(min);
320 if (min > limit)
321 limit_box->setValue(min);
325 void
326 Main_GUI::check_max()
328 int min = min_box->value();
329 int max = max_box->value();
330 int limit = limit_box->value();
331 if (max < min)
332 min_box->setValue(max);
333 if (max > limit)
334 limit_box->setValue(max);
338 void
339 Main_GUI::check_limit()
341 int min = min_box->value();
342 int max = max_box->value();
343 int limit = limit_box->value();
344 if (limit < max)
345 max_box->setValue(limit);
346 if (limit < min)
347 min_box->setValue(limit);
351 void
352 Main_GUI::check_dehint()
354 if (dehint_box->isChecked())
356 control_label->setEnabled(false);
357 control_line->setEnabled(false);
358 control_button->setEnabled(false);
360 reference_label->setEnabled(false);
361 reference_line->setEnabled(false);
362 reference_button->setEnabled(false);
364 min_label->setEnabled(false);
365 min_box->setEnabled(false);
367 max_label->setEnabled(false);
368 max_box->setEnabled(false);
370 default_label->setEnabled(false);
371 default_box->setEnabled(false);
372 fallback_label->setEnabled(false);
373 fallback_hint_or_scale_box->setEnabled(false);
374 fallback_box->setEnabled(false);
376 no_limit_box->setEnabled(false);
377 limit_label->setEnabled(false);
378 limit_box->setEnabled(false);
380 no_x_increase_box->setEnabled(false);
381 x_increase_label->setEnabled(false);
382 x_increase_box->setEnabled(false);
384 snapping_label->setEnabled(false);
385 snapping_line->setEnabled(false);
387 default_stem_width_box->setEnabled(false);
388 stem_width_label->setEnabled(false);
389 stem_width_box->setEnabled(false);
391 wincomp_box->setEnabled(false);
392 adjust_box->setEnabled(false);
393 hint_box->setEnabled(false);
394 symbol_box->setEnabled(false);
396 ref_idx_label->setEnabled(false);
397 ref_idx_box->setEnabled(false);
399 stem_label->setEnabled(false);
400 gray_box->setEnabled(false);
401 gdi_box->setEnabled(false);
402 dw_box->setEnabled(false);
404 else
406 control_label->setEnabled(true);
407 control_line->setEnabled(true);
408 control_button->setEnabled(true);
410 reference_label->setEnabled(true);
411 reference_line->setEnabled(true);
412 reference_button->setEnabled(true);
414 min_label->setEnabled(true);
415 min_box->setEnabled(true);
417 max_label->setEnabled(true);
418 max_box->setEnabled(true);
420 default_label->setEnabled(true);
421 default_box->setEnabled(true);
422 fallback_label->setEnabled(true);
423 fallback_hint_or_scale_box->setEnabled(true);
424 fallback_box->setEnabled(true);
426 no_limit_box->setEnabled(true);
427 check_no_limit();
429 no_x_increase_box->setEnabled(true);
430 check_no_x_increase();
432 snapping_label->setEnabled(true);
433 snapping_line->setEnabled(true);
435 default_stem_width_box->setEnabled(true);
436 check_default_stem_width();
438 wincomp_box->setEnabled(true);
439 adjust_box->setEnabled(true);
440 hint_box->setEnabled(true);
441 symbol_box->setEnabled(true);
443 ref_idx_label->setEnabled(true);
444 ref_idx_box->setEnabled(true);
446 stem_label->setEnabled(true);
447 gray_box->setEnabled(true);
448 gdi_box->setEnabled(true);
449 dw_box->setEnabled(true);
454 void
455 Main_GUI::check_no_limit()
457 if (no_limit_box->isChecked())
459 limit_label->setEnabled(false);
460 limit_label->setText(limit_label_text);
461 limit_box->setEnabled(false);
462 no_limit_box->setText(no_limit_box_text_with_key);
464 else
466 limit_label->setEnabled(true);
467 limit_label->setText(limit_label_text_with_key);
468 limit_box->setEnabled(true);
469 no_limit_box->setText(no_limit_box_text);
474 void
475 Main_GUI::check_no_x_increase()
477 if (no_x_increase_box->isChecked())
479 x_increase_label->setEnabled(false);
480 x_increase_label->setText(x_increase_label_text);
481 x_increase_box->setEnabled(false);
482 no_x_increase_box->setText(no_x_increase_box_text_with_key);
484 else
486 x_increase_label->setEnabled(true);
487 x_increase_label->setText(x_increase_label_text_with_key);
488 x_increase_box->setEnabled(true);
489 no_x_increase_box->setText(no_x_increase_box_text);
494 void
495 Main_GUI::check_default_stem_width()
497 if (default_stem_width_box->isChecked())
499 stem_width_label->setEnabled(false);
500 stem_width_label->setText(stem_width_label_text);
501 stem_width_box->setEnabled(false);
502 default_stem_width_box->setText(default_stem_width_box_text_with_key);
504 else
506 stem_width_label->setEnabled(true);
507 stem_width_label->setText(stem_width_label_text_with_key);
508 stem_width_box->setEnabled(true);
509 default_stem_width_box->setText(default_stem_width_box_text);
514 void
515 Main_GUI::check_run()
517 if (input_line->text().isEmpty() || output_line->text().isEmpty())
518 run_button->setEnabled(false);
519 else
520 run_button->setEnabled(true);
524 void
525 Main_GUI::absolute_input()
527 QString input_name = QDir::fromNativeSeparators(input_line->text());
528 if (!input_name.isEmpty()
529 && QDir::isRelativePath(input_name))
531 QDir cur_path(QDir::currentPath() + "/" + input_name);
532 input_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
537 void
538 Main_GUI::absolute_output()
540 QString output_name = QDir::fromNativeSeparators(output_line->text());
541 if (!output_name.isEmpty()
542 && QDir::isRelativePath(output_name))
544 QDir cur_path(QDir::currentPath() + "/" + output_name);
545 output_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
550 void
551 Main_GUI::absolute_control()
553 QString control_name = QDir::fromNativeSeparators(control_line->text());
554 if (!control_name.isEmpty()
555 && QDir::isRelativePath(control_name))
557 QDir cur_path(QDir::currentPath() + "/" + control_name);
558 control_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
563 void
564 Main_GUI::absolute_reference()
566 QString reference_name = QDir::fromNativeSeparators(reference_line->text());
567 if (!reference_name.isEmpty()
568 && QDir::isRelativePath(reference_name))
570 QDir cur_path(QDir::currentPath() + "/" + reference_name);
571 reference_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
576 void
577 Main_GUI::set_ref_idx_box_max()
579 QString reference_name = QDir::fromNativeSeparators(reference_line->text());
581 FT_Library library = NULL;
582 FT_Face face = NULL;
583 FT_Error error;
585 // we don't handle errors
586 // since `TTF_autohint' checks the reference font (and index) later on
587 error = FT_Init_FreeType(&library);
588 if (!error)
589 error = FT_New_Face(library, qPrintable(reference_name), -1, &face);
591 ref_idx_box->setRange(0, error ? 100 : int(face->num_faces - 1));
593 FT_Done_Face(face);
594 FT_Done_FreeType(library);
598 void
599 Main_GUI::check_number_set()
601 QString text = snapping_line->text();
602 QString qs;
604 // construct ASCII string from arbitrary Unicode data;
605 // the idea is to accept, say, CJK fullwidth digits also
606 for (int i = 0; i < text.size(); i++)
608 QChar c = text.at(i);
610 int digit = c.digitValue();
611 if (digit >= 0)
612 qs += QString::number(digit);
613 else if (c.isSpace())
614 qs += ' ';
615 // U+30FC KATAGANA-HIRAGANA PROLONGED SOUND MARK is assigned
616 // to the `-' key in some Japanese input methods
617 else if (c.category() == QChar::Punctuation_Dash
618 || c == QChar(0x30FC))
619 qs += '-';
620 // various Unicode COMMA characters,
621 // including representation forms
622 else if (c == QChar(',')
623 || c == QChar(0x055D)
624 || c == QChar(0x060C)
625 || c == QChar(0x07F8)
626 || c == QChar(0x1363)
627 || c == QChar(0x1802)
628 || c == QChar(0x1808)
629 || c == QChar(0x3001)
630 || c == QChar(0xA4FE)
631 || c == QChar(0xA60D)
632 || c == QChar(0xA6F5)
633 || c == QChar(0xFE10)
634 || c == QChar(0xFE11)
635 || c == QChar(0xFE50)
636 || c == QChar(0xFE51)
637 || c == QChar(0xFF0C)
638 || c == QChar(0xFF64))
639 qs += ',';
640 else
641 qs += c; // we do error handling below
644 if (x_height_snapping_exceptions)
645 number_set_free(x_height_snapping_exceptions);
647 QByteArray str = qs.toLocal8Bit();
648 const char* s = number_set_parse(str.constData(),
649 &x_height_snapping_exceptions,
650 6, 0x7FFF);
651 if (s && *s)
653 statusBar()->setStyleSheet("color: red;");
654 if (x_height_snapping_exceptions == NUMBERSET_ALLOCATION_ERROR)
655 statusBar()->showMessage(
656 tr("allocation error"));
657 else if (x_height_snapping_exceptions == NUMBERSET_INVALID_CHARACTER)
658 statusBar()->showMessage(
659 tr("invalid character (use digits, dashes, commas, and spaces)"));
660 else if (x_height_snapping_exceptions == NUMBERSET_OVERFLOW)
661 statusBar()->showMessage(
662 tr("overflow"));
663 else if (x_height_snapping_exceptions == NUMBERSET_INVALID_RANGE)
664 statusBar()->showMessage(
665 tr("invalid range (minimum is 6, maximum is 32767)"));
666 else if (x_height_snapping_exceptions == NUMBERSET_OVERLAPPING_RANGES)
667 statusBar()->showMessage(
668 tr("overlapping ranges"));
669 else if (x_height_snapping_exceptions == NUMBERSET_NOT_ASCENDING)
670 statusBar()->showMessage(
671 tr("values und ranges must be specified in ascending order"));
673 snapping_line->setText(qs);
674 snapping_line->setFocus(Qt::OtherFocusReason);
675 snapping_line->setCursorPosition(int(s - str.constData()));
677 x_height_snapping_exceptions = NULL;
679 else
681 // normalize if there is no error
682 char* new_str = number_set_show(x_height_snapping_exceptions,
683 6, 0x7FFF);
684 snapping_line->setText(new_str);
685 free(new_str);
690 void
691 Main_GUI::check_family_suffix()
693 QByteArray text = family_suffix_line->text().toLocal8Bit();
694 const char* s = text.constData();
696 if (const char* pos = ::check_family_suffix(s))
698 statusBar()->setStyleSheet("color: red;");
699 statusBar()->showMessage(
700 tr("invalid character (use printable ASCII except %()/<>[]{})"));
701 family_suffix_line->setFocus(Qt::OtherFocusReason);
702 family_suffix_line->setCursorPosition(int(pos - s));
707 void
708 Main_GUI::clear_status_bar()
710 statusBar()->clearMessage();
711 statusBar()->setStyleSheet("");
716 Main_GUI::check_filenames(const QString& input_name,
717 const QString& output_name,
718 const QString& control_name,
719 const QString& reference_name)
721 if (!QFile::exists(input_name))
723 QMessageBox::warning(
724 this,
725 "TTFautohint",
726 tr("The file %1 cannot be found.")
727 .arg(QUOTE_STRING(QDir::toNativeSeparators(input_name))),
728 QMessageBox::Ok,
729 QMessageBox::Ok);
730 return 0;
733 if (input_name == output_name)
735 QMessageBox::warning(
736 this,
737 "TTFautohint",
738 tr("Input and output file names must be different."),
739 QMessageBox::Ok,
740 QMessageBox::Ok);
741 return 0;
744 // silently overwrite if watching is active
745 if (QFile::exists(output_name) && !watch_box->isChecked())
747 int ret = QMessageBox::warning(
748 this,
749 "TTFautohint",
750 tr("The file %1 already exists.\n"
751 "Overwrite?")
752 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name))),
753 QMessageBox::Yes | QMessageBox::No,
754 QMessageBox::No);
755 if (ret == QMessageBox::No)
756 return 0;
759 if (!control_name.isEmpty() && !QFile::exists(control_name))
761 QMessageBox::warning(
762 this,
763 "TTFautohint",
764 tr("The file %1 cannot be found.")
765 .arg(QUOTE_STRING(QDir::toNativeSeparators(control_name))),
766 QMessageBox::Ok,
767 QMessageBox::Ok);
768 return 0;
771 if (!reference_name.isEmpty() && !QFile::exists(reference_name))
773 QMessageBox::warning(
774 this,
775 "TTFautohint",
776 tr("The file %1 cannot be found.")
777 .arg(QUOTE_STRING(QDir::toNativeSeparators(reference_name))),
778 QMessageBox::Ok,
779 QMessageBox::Ok);
780 return 0;
783 return 1;
788 Main_GUI::open_files(const QString& input_name,
789 FILE** in,
790 const QString& output_name,
791 FILE** out,
792 const QString& control_name,
793 FILE** control,
794 const QString& reference_name,
795 FILE** reference)
797 const int buf_len = 1024;
798 char buf[buf_len];
800 *in = fopen(qPrintable(input_name), "rb");
801 if (!*in)
803 strerror_r(errno, buf, buf_len);
804 QMessageBox::warning(
805 this,
806 "TTFautohint",
807 tr("The following error occurred while opening input file %1:\n")
808 .arg(QUOTE_STRING(QDir::toNativeSeparators(input_name)))
809 + QString::fromLocal8Bit(buf),
810 QMessageBox::Ok,
811 QMessageBox::Ok);
812 return 0;
815 *out = fopen(qPrintable(output_name), "wb");
816 if (!*out)
818 strerror_r(errno, buf, buf_len);
819 QMessageBox::warning(
820 this,
821 "TTFautohint",
822 tr("The following error occurred while opening output file %1:\n")
823 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name)))
824 + QString::fromLocal8Bit(buf),
825 QMessageBox::Ok,
826 QMessageBox::Ok);
827 return 0;
830 if (!control_name.isEmpty())
832 *control = fopen(qPrintable(control_name), "r");
833 if (!*control)
835 strerror_r(errno, buf, buf_len);
836 QMessageBox::warning(
837 this,
838 "TTFautohint",
839 tr("The following error occurred"
840 " while opening control instructions file %1:\n")
841 .arg(QUOTE_STRING(QDir::toNativeSeparators(control_name)))
842 + QString::fromLocal8Bit(buf),
843 QMessageBox::Ok,
844 QMessageBox::Ok);
845 return 0;
848 else
849 *control = NULL;
851 if (!reference_name.isEmpty())
853 *reference = fopen(qPrintable(reference_name), "rb");
854 if (!*reference)
856 strerror_r(errno, buf, buf_len);
857 QMessageBox::warning(
858 this,
859 "TTFautohint",
860 tr("The following error occurred"
861 " while opening blue zone reference file %1:\n")
862 .arg(QUOTE_STRING(QDir::toNativeSeparators(reference_name)))
863 + QString::fromLocal8Bit(buf),
864 QMessageBox::Ok,
865 QMessageBox::Ok);
866 return 0;
869 else
870 *reference = NULL;
872 return 1;
876 void
877 Main_GUI::check_watch()
879 if (watch_box->isChecked())
881 // file watching gets started in the `run' function
882 check = DoCheck;
884 else
885 stop_watching();
889 void
890 Main_GUI::start_timer()
892 // we delay the file watching action, mainly to ensure
893 // that newly generated files have been completely written to disk
894 check = CheckNow;
895 timer->start();
899 void
900 Main_GUI::stop_watching()
902 check = DoCheck;
903 if (!fileinfo_input_file.fileName().isEmpty())
904 file_watcher->removePath(fileinfo_input_file.fileName());
905 if (!fileinfo_control_file.fileName().isEmpty())
906 file_watcher->removePath(fileinfo_control_file.fileName());
907 if (!fileinfo_reference_file.fileName().isEmpty())
908 file_watcher->removePath(fileinfo_reference_file.fileName());
912 void
913 Main_GUI::watch_files()
915 if (fileinfo_input_file.exists()
916 && fileinfo_input_file.isReadable()
917 && (fileinfo_control_file.fileName().isEmpty()
918 ? true
919 : (fileinfo_control_file.exists()
920 && fileinfo_control_file.isReadable()))
921 && (fileinfo_reference_file.fileName().isEmpty()
922 ? true
923 : (fileinfo_reference_file.exists()
924 && fileinfo_reference_file.isReadable())))
926 QDateTime modified_input = fileinfo_input_file.lastModified();
927 QDateTime modified_control = fileinfo_control_file.lastModified();
928 QDateTime modified_reference = fileinfo_reference_file.lastModified();
929 // XXX make this configurable
930 if (datetime_input_file.msecsTo(modified_input) > 1000
931 || datetime_control_file.msecsTo(modified_control) > 1000
932 || datetime_reference_file.msecsTo(modified_reference) > 1000)
934 check = CheckNow;
935 run(); // this function sets `datetime_XXX'
937 else
939 // restart timer for symlinks
940 if (watch_box->isChecked())
942 if (fileinfo_input_file.isSymLink()
943 || fileinfo_control_file.isSymLink()
944 || fileinfo_reference_file.isSymLink())
945 timer->start();
949 else
951 if (check == DoCheck)
952 check = CheckLater;
953 else if (check == CheckLater)
954 check = CheckNow;
956 run(); // let this routine handle all errors
961 extern "C" {
963 struct GUI_Progress_Data
965 long last_sfnt;
966 bool begin;
967 QProgressDialog* dialog;
971 #undef TRDOMAIN
972 #define TRDOMAIN "GuiProgress"
974 static int
975 gui_progress(long curr_idx,
976 long num_glyphs,
977 long curr_sfnt,
978 long num_sfnts,
979 void* user)
981 GUI_Progress_Data* data = static_cast<GUI_Progress_Data*>(user);
983 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
985 data->dialog->setLabelText(Tr("Auto-hinting subfont %1 of %2"
986 " with %3 glyphs...")
987 .arg(curr_sfnt + 1)
988 .arg(num_sfnts)
989 .arg(num_glyphs));
991 if (curr_sfnt + 1 == num_sfnts)
993 data->dialog->setAutoReset(true);
994 data->dialog->setAutoClose(true);
996 else
998 data->dialog->setAutoReset(false);
999 data->dialog->setAutoClose(false);
1002 data->last_sfnt = curr_sfnt;
1003 data->begin = true;
1006 if (data->begin)
1008 if (num_sfnts == 1)
1009 data->dialog->setLabelText(Tr("Auto-hinting %1 glyphs...")
1010 .arg(num_glyphs));
1011 data->dialog->setMaximum(int(num_glyphs - 1));
1013 data->begin = false;
1016 data->dialog->setValue(int(curr_idx));
1018 if (data->dialog->wasCanceled())
1019 return 1;
1021 return 0;
1025 struct GUI_Error_Data
1027 Main_GUI* gui;
1028 QLocale* locale;
1029 QString output_name;
1030 QString control_name;
1031 QString reference_name;
1032 int* ignore_restrictions_p;
1033 bool retry;
1037 #undef TRDOMAIN
1038 #define TRDOMAIN "GuiError"
1040 static void
1041 gui_error(TA_Error error,
1042 const char* error_string,
1043 unsigned int errlinenum,
1044 const char* errline,
1045 const char* errpos,
1046 void* user)
1048 GUI_Error_Data* data = static_cast<GUI_Error_Data*>(user);
1049 QLocale* locale = data->locale; // for QUOTE_STRING_LITERAL
1051 if (!error)
1052 return;
1054 if (error == TA_Err_Canceled)
1056 else if (error == TA_Err_Invalid_FreeType_Version)
1057 QMessageBox::critical(
1058 data->gui,
1059 "TTFautohint",
1060 Tr("FreeType version 2.4.5 or higher is needed.\n"
1061 "Are you perhaps using a wrong FreeType DLL?"),
1062 QMessageBox::Ok,
1063 QMessageBox::Ok);
1064 else if (error == TA_Err_Invalid_Font_Type)
1065 QMessageBox::warning(
1066 data->gui,
1067 "TTFautohint",
1068 Tr("This font is not a valid font"
1069 " in SFNT format with TrueType outlines.\n"
1070 "In particular, CFF outlines are not supported."),
1071 QMessageBox::Ok,
1072 QMessageBox::Ok);
1073 else if (error == TA_Err_Already_Processed)
1074 QMessageBox::warning(
1075 data->gui,
1076 "TTFautohint",
1077 Tr("This font has already been processed by TTFautohint."),
1078 QMessageBox::Ok,
1079 QMessageBox::Ok);
1080 else if (error == TA_Err_Missing_Legal_Permission)
1082 int yesno = QMessageBox::warning(
1083 data->gui,
1084 "TTFautohint",
1085 Tr("Bit 1 in the %1 field of the %2 table is set:"
1086 " This font must not be modified"
1087 " without permission of the legal owner.\n"
1088 "Do you have such a permission?")
1089 .arg(QUOTE_STRING_LITERAL("fsType"))
1090 .arg(QUOTE_STRING_LITERAL("OS/2")),
1091 QMessageBox::Yes | QMessageBox::No,
1092 QMessageBox::No);
1093 if (yesno == QMessageBox::Yes)
1095 *data->ignore_restrictions_p = true;
1096 data->retry = true;
1099 else if (error == TA_Err_Missing_Unicode_CMap)
1100 QMessageBox::warning(
1101 data->gui,
1102 "TTFautohint",
1103 Tr("The input font doesn't contain a Unicode character map.\n"
1104 "Maybe you haven't set the %1 checkbox?")
1105 .arg(QUOTE_STRING_LITERAL(Tr("Symbol Font"))),
1106 QMessageBox::Ok,
1107 QMessageBox::Ok);
1108 else if (error == TA_Err_Missing_Symbol_CMap)
1109 QMessageBox::warning(
1110 data->gui,
1111 "TTFautohint",
1112 Tr("The input font does neither contain a symbol"
1113 " nor a character map."),
1114 QMessageBox::Ok,
1115 QMessageBox::Ok);
1116 else if (error == TA_Err_Missing_Glyph)
1117 QMessageBox::warning(
1118 data->gui,
1119 "TTFautohint",
1120 Tr("No glyph for a standard character"
1121 " to derive standard width and height.\n"
1122 "Please check the documentation for a list of"
1123 " script-specific standard characters.\n"
1124 "\n"
1125 "Set the %1 checkbox if you want to circumvent this test.")
1126 .arg(QUOTE_STRING_LITERAL(Tr("Symbol Font"))),
1127 QMessageBox::Ok,
1128 QMessageBox::Ok);
1129 else if (error >= 0x200 && error < 0x300)
1130 QMessageBox::warning(
1131 data->gui,
1132 "TTFautohint",
1133 QString::fromLocal8Bit("%1:%2:%3: %4 (0x%5)<br>"
1134 "<tt> %6<br>"
1135 " %7</tt>")
1136 .arg(data->control_name)
1137 .arg(errlinenum)
1138 .arg(int(errpos - errline + 1))
1139 .arg(error_string)
1140 .arg(error, 2, 16, QLatin1Char('0'))
1141 .arg(errline)
1142 .arg('^', int(errpos - errline + 1))
1143 .replace(" ", "&nbsp;"),
1144 QMessageBox::Ok,
1145 QMessageBox::Ok);
1146 else if (error >= 0x300 && error < 0x400)
1147 QMessageBox::warning(
1148 data->gui,
1149 "TTFautohint",
1150 Tr("Error code 0x%1 while loading blue zone reference file:\n")
1151 .arg(error - 0x300, 2, 16, QLatin1Char('0'))
1152 + QString::fromLocal8Bit(error_string),
1153 QMessageBox::Ok,
1154 QMessageBox::Ok);
1155 else
1156 QMessageBox::warning(
1157 data->gui,
1158 "TTFautohint",
1159 Tr("Error code 0x%1 while autohinting font:\n")
1160 .arg(error, 2, 16, QLatin1Char('0'))
1161 + QString::fromLocal8Bit(error_string),
1162 QMessageBox::Ok,
1163 QMessageBox::Ok);
1165 if (QFile::exists(data->output_name)
1166 && remove(qPrintable(data->output_name)))
1168 const int buf_len = 1024;
1169 char buf[buf_len];
1171 strerror_r(errno, buf, buf_len);
1172 QMessageBox::warning(
1173 data->gui,
1174 "TTFautohint",
1175 Tr("The following error occurred while removing output file %1:\n")
1176 .arg(QUOTE_STRING(QDir::toNativeSeparators(data->output_name)))
1177 + QString::fromLocal8Bit(buf),
1178 QMessageBox::Ok,
1179 QMessageBox::Ok);
1183 } // extern "C"
1186 void
1187 Main_GUI::run()
1189 clear_status_bar();
1191 if (check == CheckLater)
1193 timer->start();
1194 return;
1197 QString input_name = QDir::fromNativeSeparators(input_line->text());
1198 QString output_name = QDir::fromNativeSeparators(output_line->text());
1199 QString control_name = QDir::fromNativeSeparators(control_line->text());
1200 QString reference_name = QDir::fromNativeSeparators(reference_line->text());
1201 if (!check_filenames(input_name, output_name, control_name, reference_name))
1203 stop_watching();
1204 return;
1207 // we need C file descriptors for communication with TTF_autohint
1208 FILE* input;
1209 FILE* output;
1210 FILE* control;
1211 FILE* reference;
1213 again:
1214 if (!open_files(input_name, &input,
1215 output_name, &output,
1216 control_name, &control,
1217 reference_name, &reference))
1219 stop_watching();
1220 return;
1223 QProgressDialog dialog;
1224 dialog.setCancelButtonText(tr("Cancel"));
1225 dialog.setMinimumDuration(1000);
1226 dialog.setWindowModality(Qt::WindowModal);
1228 TA_Info_Func info_func = info;
1229 TA_Info_Post_Func info_post_func = info_post;
1230 GUI_Progress_Data gui_progress_data = {-1, true, &dialog};
1231 GUI_Error_Data gui_error_data = {this, locale,
1232 output_name, control_name, reference_name,
1233 &ignore_restrictions, false};
1235 fileinfo_input_file.setFile(input_name);
1236 fileinfo_control_file.setFile(control_name);
1237 fileinfo_reference_file.setFile(reference_name);
1239 // prepare C strings
1240 QByteArray ctrl_name = fileinfo_control_file.fileName().toLocal8Bit();
1241 QByteArray ref_name = fileinfo_reference_file.fileName().toLocal8Bit();
1242 QByteArray except_str = x_height_snapping_exceptions_string.toLocal8Bit();
1243 QByteArray fam_suff = family_suffix_line->text().toLocal8Bit();
1245 Info_Data info_data;
1247 info_data.info_string = NULL; // must be deallocated after use
1248 info_data.info_string_wide = NULL; // must be deallocated after use
1249 info_data.info_string_len = 0;
1250 info_data.info_string_wide_len = 0;
1252 info_data.control_name = ctrl_name.isEmpty() ? NULL
1253 : ctrl_name.constData();
1254 info_data.reference_name = ref_name.isEmpty() ? NULL
1255 : ref_name.constData();
1256 info_data.reference_index = ref_idx_box->value();
1258 info_data.hinting_range_min = min_box->value();
1259 info_data.hinting_range_max = max_box->value();
1260 info_data.hinting_limit = no_limit_box->isChecked()
1262 : limit_box->value();
1264 info_data.gray_strong_stem_width = gray_box->isChecked();
1265 info_data.gdi_cleartype_strong_stem_width = gdi_box->isChecked();
1266 info_data.dw_cleartype_strong_stem_width = dw_box->isChecked();
1268 info_data.increase_x_height = no_x_increase_box->isChecked()
1270 : x_increase_box->value();
1271 info_data.x_height_snapping_exceptions_string = except_str.constData();
1273 info_data.family_suffix = fam_suff.constData();
1274 info_data.family_data_head = NULL;
1276 info_data.fallback_stem_width = default_stem_width_box->isChecked()
1278 : stem_width_box->value();
1280 info_data.windows_compatibility = wincomp_box->isChecked();
1281 info_data.adjust_subglyphs = adjust_box->isChecked();
1282 info_data.hint_composites = hint_box->isChecked();
1283 info_data.symbol = symbol_box->isChecked();
1284 info_data.fallback_scaling = fallback_hint_or_scale_box->currentIndex();
1285 info_data.no_info = info_box->currentIndex() == 0;
1286 info_data.detailed_info = info_box->currentIndex() == 2;
1287 info_data.dehint = dehint_box->isChecked();
1288 info_data.TTFA_info = TTFA_box->isChecked();
1290 strncpy(info_data.default_script,
1291 script_names[default_box->currentIndex()].tag,
1292 sizeof (info_data.default_script));
1293 strncpy(info_data.fallback_script,
1294 script_names[fallback_box->currentIndex()].tag,
1295 sizeof (info_data.fallback_script));
1297 if (info_box->currentIndex())
1299 int ret = build_version_string(&info_data);
1300 if (ret == 1)
1301 QMessageBox::information(
1302 this,
1303 "TTFautohint",
1304 tr("Can't allocate memory for <b>TTFautohint</b> options string"
1305 " in <i>name</i> table."),
1306 QMessageBox::Ok,
1307 QMessageBox::Ok);
1308 else if (ret == 2)
1309 QMessageBox::information(
1310 this,
1311 "TTFautohint",
1312 tr("<b>TTFautohint</b> options string"
1313 " in <i>name</i> table too long."),
1314 QMessageBox::Ok,
1315 QMessageBox::Ok);
1318 if (!*info_data.family_suffix)
1319 info_post_func = NULL;
1321 if (info_data.symbol
1322 && info_data.fallback_stem_width
1323 && info_data.fallback_scaling)
1324 QMessageBox::information(
1325 this,
1326 "TTFautohint",
1327 tr("Setting a fallback stem width for a symbol font"
1328 " with fallback scaling only has no effect."),
1329 QMessageBox::Ok,
1330 QMessageBox::Ok);
1332 datetime_input_file = fileinfo_input_file.lastModified();
1333 datetime_control_file = fileinfo_control_file.lastModified();
1334 datetime_reference_file = fileinfo_reference_file.lastModified();
1336 QByteArray snapping_string = snapping_line->text().toLocal8Bit();
1338 TA_Error error =
1339 TTF_autohint("in-file, out-file, control-file, reference-file,"
1340 "reference-index, reference-name,"
1341 "hinting-range-min, hinting-range-max,"
1342 "hinting-limit,"
1343 "gray-strong-stem-width,"
1344 "gdi-cleartype-strong-stem-width,"
1345 "dw-cleartype-strong-stem-width,"
1346 "progress-callback, progress-callback-data,"
1347 "error-callback, error-callback-data,"
1348 "info-callback, info-post-callback, info-callback-data,"
1349 "ignore-restrictions,"
1350 "windows-compatibility,"
1351 "adjust-subglyphs,"
1352 "hint-composites,"
1353 "increase-x-height,"
1354 "x-height-snapping-exceptions, fallback-stem-width,"
1355 "default-script,"
1356 "fallback-script, fallback-scaling,"
1357 "symbol, dehint, TTFA-info",
1358 input, output, control, reference,
1359 info_data.reference_index, info_data.reference_name,
1360 info_data.hinting_range_min, info_data.hinting_range_max,
1361 info_data.hinting_limit,
1362 info_data.gray_strong_stem_width,
1363 info_data.gdi_cleartype_strong_stem_width,
1364 info_data.dw_cleartype_strong_stem_width,
1365 gui_progress, &gui_progress_data,
1366 gui_error, &gui_error_data,
1367 info_func, info_post_func, &info_data,
1368 ignore_restrictions,
1369 info_data.windows_compatibility,
1370 info_data.adjust_subglyphs,
1371 info_data.hint_composites,
1372 info_data.increase_x_height,
1373 snapping_string.constData(), info_data.fallback_stem_width,
1374 info_data.default_script,
1375 info_data.fallback_script, info_data.fallback_scaling,
1376 info_data.symbol, info_data.dehint, info_data.TTFA_info);
1378 if (info_box->currentIndex())
1380 free(info_data.info_string);
1381 free(info_data.info_string_wide);
1384 fclose(input);
1385 fclose(output);
1386 if (control)
1387 fclose(control);
1388 if (reference)
1389 fclose(reference);
1391 if (error)
1393 // retry if there is a user request to do so (handled in `gui_error')
1394 if (gui_error_data.retry)
1395 goto again;
1397 stop_watching();
1399 else
1401 statusBar()->showMessage(tr("Auto-hinting finished")
1402 + " ("
1403 + QDateTime::currentDateTime()
1404 .toString(Qt::TextDate)
1405 + ").");
1407 // we have successfully processed a file;
1408 // start file watching now if requested
1409 if (watch_box->isChecked())
1411 check = DoCheck;
1413 // Qt's file watcher doesn't handle symlinks;
1414 // we thus fall back to polling
1415 if (fileinfo_input_file.isSymLink()
1416 || fileinfo_control_file.isSymLink()
1417 || fileinfo_reference_file.isSymLink())
1418 timer->start();
1419 else
1421 file_watcher->addPath(input_name);
1422 file_watcher->addPath(control_name);
1423 file_watcher->addPath(reference_name);
1430 // XXX distances are specified in pixels,
1431 // making the layout dependent on the output device resolution
1432 void
1433 Main_GUI::create_layout(bool horizontal_layout)
1436 // file stuff
1438 QCompleter* completer = new QCompleter(this);
1439 QFileSystemModel* model = new QFileSystemModel(completer);
1440 model->setRootPath(QDir::rootPath());
1441 completer->setModel(model);
1443 input_label = new QLabel(tr("&Input Font:"));
1444 input_line = new Drag_Drop_Line_Edit(DRAG_DROP_TRUETYPE);
1445 input_button = new QPushButton(tr("Browse..."));
1446 input_label->setBuddy(input_line);
1447 // enforce rich text to get nice word wrapping
1448 input_label->setToolTip(
1449 tr("<b></b>The input file, either a TrueType font (TTF),"
1450 " TrueType collection (TTC), or a TrueType-based OpenType font."));
1451 input_line->setCompleter(completer);
1453 output_label = new QLabel(tr("&Output Font:"));
1454 output_line = new Drag_Drop_Line_Edit(DRAG_DROP_TRUETYPE);
1455 output_button = new QPushButton(tr("Browse..."));
1456 output_label->setBuddy(output_line);
1457 output_label->setToolTip(
1458 tr("<b></b>The output file, which will be essentially identical"
1459 " to the input font but will contain new, generated hints."));
1460 output_line->setCompleter(completer);
1462 control_label = new QLabel(tr("Control Instructions Fil&e:"));
1463 control_line = new Drag_Drop_Line_Edit(DRAG_DROP_ANY);
1464 control_button = new QPushButton(tr("Browse..."));
1465 control_label->setBuddy(control_line);
1466 // we use the non-breaking hyphen U+2011 (&#8209;) where necessary
1467 QString tooltip_string =
1468 tr("<p>An optional control instructions file to tweak hinting"
1469 " and to override glyph assignments to styles."
1470 " This text file contains entries"
1471 " of one of the following syntax forms"
1472 " (with brackets indicating optional elements).<br>"
1473 "&nbsp;<br>"
1475 "&nbsp;&nbsp;[&nbsp;<i>subfont&#8209;idx</i>&nbsp;]"
1476 "&nbsp;&nbsp;<i>script</i>"
1477 "&nbsp;&nbsp;<i>feature</i>"
1478 "&nbsp;&nbsp;<tt>@</tt>&nbsp;<i>glyph&#8209;ids</i><br>"
1480 "&nbsp;&nbsp;[&nbsp;<i>subfont&#8209;idx</i>&nbsp;]"
1481 "&nbsp;&nbsp;<i>glyph&#8209;id</i>"
1482 "&nbsp;&nbsp;<tt>left</tt>&nbsp;|&nbsp;<tt>right</tt>&nbsp;<i>points</i>"
1483 "&nbsp;&nbsp;[&nbsp;<tt>(</tt><i>left&#8209;offset</i><tt>,"
1484 "</tt><i>right&#8209;offset</i><tt>)</tt>&nbsp;]<br>"
1486 "&nbsp;&nbsp;[&nbsp;<i>subfont&#8209;idx</i>&nbsp;]"
1487 "&nbsp;&nbsp;<i>glyph&#8209;id</i>"
1488 "&nbsp;&nbsp;<tt>nodir</tt>&nbsp;<i>points</i><br>"
1490 "&nbsp;&nbsp;[&nbsp;<i>subfont&#8209;idx</i>&nbsp;]"
1491 "&nbsp;&nbsp;<i>glyph&#8209;id</i>"
1492 "&nbsp;&nbsp;<tt>touch</tt>&nbsp;|&nbsp;<tt>point</tt>&nbsp;<i>points</i>"
1493 "&nbsp;&nbsp;[&nbsp;<tt>xshift</tt>&nbsp;<i>shift</i>&nbsp;]"
1494 "&nbsp;&nbsp;[&nbsp;<tt>yshift</tt>&nbsp;<i>shift</i>&nbsp;]"
1495 "&nbsp;&nbsp;<tt>@</tt>&nbsp;<i>ppems</i><br>"
1496 "&nbsp;<br>"
1498 "<i>subfont&#8209;idx</i> gives the subfont index in a TTC,"
1499 " <i>glyph&#8209;id</i> is a glyph name or index.<br>"
1500 "&nbsp;<br>"
1502 "<i>script</i> and <i>feature</i> are four-letter tags"
1503 " (like <tt>cyrl</tt> for the Cyrillic script"
1504 " or <tt>subs</tt> for the subscript feature)"
1505 " that define a style the <i>glyph&#8209;ids</i> are assigned to."
1506 " <i>glyph&#8209;ids</i> is a comma-separated list of"
1507 " <i>glyph&#8209;id</i> values and value ranges.<br>"
1508 "&nbsp;<br>"
1510 "<tt>left</tt> (<tt>right</tt>) creates one-point segments"
1511 " with direction left (right), possibly having a width (in font units)"
1512 " given by <i>left&#8209;offset</i> and <i>right&#8209;offset</i>"
1513 " relative to the corresponding points.<br>"
1514 "&nbsp;<br>"
1516 "<tt>nodir</tt> removes points from horizontal segments,"
1517 " making them <i>weak</i> points.<br>"
1518 "&nbsp;<br>"
1520 "<tt>touch </tt> (<tt>point</tt>) defines delta exceptions"
1521 " to be applied before (after) the final"
1522 " <tt>IUP</tt> bytecode instructions."
1523 " <tt>touch</tt> also touches points, making them <i>strong</i>."
1524 " In ClearType mode, <tt>point</tt> and <tt>xshift</tt>"
1525 " have no effect.<br>"
1526 "&nbsp;<br>"
1528 "x and y <i>shift</i> values are in the range [-1;1],"
1529 " rounded to multiples of 1/8px.<br>"
1531 "<i>points</i> and <i>ppems</i> are ranges for point indices"
1532 " and ppem values as with x&nbsp;height snapping exceptions.<br>"
1534 "Keywords <tt>left</tt>, <tt>right</tt>, <tt>nodir</tt>,"
1535 " <tt>point</tt>, <tt>touch</tt>, <tt>xshift</tt>, and"
1536 " <tt>yshift</tt> can be abbreviated as <tt>l</tt>, <tt>r</tt>,"
1537 " <tt>n</tt>, <tt>p</tt>, <tt>t</tt>, <tt>x</tt>, and <tt>y</tt>,"
1538 " respectively.<br>"
1540 "Control instruction entries are separated"
1541 " by character&nbsp;<tt>;</tt> or by a newline.<br>"
1543 "A trailing character&nbsp;<tt>\\</tt> continues the current line"
1544 " on the next line.<br>"
1546 "<tt>#</tt> starts a line comment, which gets ignored."
1547 " Empty lines are ignored, too.</p>"
1549 "Examples:<br>"
1550 "&nbsp;&nbsp;<tt>cyrl sups @ one.sups-nine.sups, zero.sups</tt><br>"
1551 "&nbsp;&nbsp;<tt>Q left 38 (-70,20)</tt><br>"
1552 "&nbsp;&nbsp;<tt>Adieresis touch 3-6 yshift 0.25 @ 13</tt>");
1554 control_label->setToolTip(tooltip_string);
1555 control_line->setCompleter(completer);
1557 reference_label = new QLabel(tr("Blue &Zone Reference Font:"));
1558 reference_line = new Drag_Drop_Line_Edit(DRAG_DROP_TRUETYPE);
1559 reference_button = new QPushButton(tr("Browse..."));
1560 reference_label->setBuddy(reference_line);
1561 reference_label->setToolTip(
1562 tr("<b></b>A reference font file"
1563 " from which all blue zone values are taken."));
1564 reference_line->setCompleter(completer);
1566 ref_idx_label = new QLabel(tr("Reference Face Index:"));
1567 ref_idx_box = new QSpinBox;
1568 ref_idx_label->setBuddy(ref_idx_box);
1569 ref_idx_label->setToolTip(
1570 tr("The face index of the blue zone reference font to be used"
1571 " in case it is a TrueType Collection (<tt>.ttc</tt>)."));
1572 ref_idx_box->setKeyboardTracking(false);
1573 // the range maximum gets updated interactively
1574 // after a (more or less) valid reference font has been selected
1575 ref_idx_box->setRange(0, 100);
1578 // minmax controls
1580 min_label = new QLabel(tr("Hint Set Range Mi&nimum:"));
1581 min_box = new QSpinBox;
1582 min_label->setBuddy(min_box);
1583 min_label->setToolTip(
1584 tr("The minimum PPEM value of the range for which"
1585 " <b>TTFautohint</b> computes <i>hint sets</i>."
1586 " A hint set for a given PPEM value hints this size optimally."
1587 " The larger the range, the more hint sets are considered,"
1588 " usually increasing the size of the bytecode.<br>"
1589 "Note that changing this range doesn't influence"
1590 " the <i>gasp</i> table:"
1591 " Hinting is enabled for all sizes."));
1592 min_box->setKeyboardTracking(false);
1593 min_box->setRange(2, 10000);
1595 max_label = new QLabel(tr("Hint Set Range Ma&ximum:"));
1596 max_box = new QSpinBox;
1597 max_label->setBuddy(max_box);
1598 max_label->setToolTip(
1599 tr("The maximum PPEM value of the range for which"
1600 " <b>TTFautohint</b> computes <i>hint sets</i>."
1601 " A hint set for a given PPEM value hints this size optimally."
1602 " The larger the range, the more hint sets are considered,"
1603 " usually increasing the size of the bytecode.<br>"
1604 "Note that changing this range doesn't influence"
1605 " the <i>gasp</i> table:"
1606 " Hinting is enabled for all sizes."));
1607 max_box->setKeyboardTracking(false);
1608 max_box->setRange(2, 10000);
1611 // OpenType default script
1613 default_label = new QLabel(tr("Defa&ult Script:"));
1614 default_box = new QComboBox;
1615 default_label->setBuddy(default_box);
1616 default_label->setToolTip(
1617 tr("This sets the default script for OpenType features:"
1618 " After applying all features that are handled specially"
1619 " (for example small caps or superscript glyphs),"
1620 " <b>TTFautohint</b> uses this value for the remaining features."
1622 "<p>In most cases, you don't want to change this value.</p>"));
1623 for (int i = 0; script_names[i].tag; i++)
1625 // XXX: how to provide translations?
1626 default_box->insertItem(i,
1627 QString("%1 (%2)")
1628 .arg(script_names[i].tag)
1629 .arg(script_names[i].description));
1633 // hinting and fallback controls
1635 fallback_label = new QLabel(tr("Fallbac&k Script"));
1636 fallback_hint_or_scale_box = new QComboBox;
1637 fallback_box = new QComboBox;
1638 fallback_label->setBuddy(fallback_hint_or_scale_box);
1639 fallback_label->setToolTip(
1640 tr("This sets the fallback script for glyphs"
1641 " that <b>TTFautohint</b> can't map to a script automatically."
1642 " Either hinting with the script's blue zone values"
1643 " or simple scaling with the script's scaling value"
1644 " can be selected."));
1645 fallback_hint_or_scale_box->insertItem(fallback_do_scale, tr("Scaling:"));
1646 fallback_hint_or_scale_box->insertItem(fallback_do_hint, tr("Hinting:"));
1647 for (int i = 0; script_names[i].tag; i++)
1649 // XXX: how to provide translations?
1650 fallback_box->insertItem(i,
1651 QString("%1 (%2)")
1652 .arg(script_names[i].tag)
1653 .arg(script_names[i].description));
1657 // hinting limit
1659 limit_label_text_with_key = tr("Hinting &Limit:");
1660 limit_label_text = tr("Hinting Limit:");
1661 limit_label = new QLabel(limit_label_text_with_key);
1662 limit_box = new QSpinBox;
1663 limit_label->setBuddy(limit_box);
1664 limit_label->setToolTip(
1665 tr("Switch off hinting for PPEM values exceeding this limit."
1666 " Changing this value does not influence the size of the bytecode.<br>"
1667 "Note that <b>TTFautohint</b> handles this feature"
1668 " in the output font's bytecode and not in the <i>gasp</i> table."));
1669 limit_box->setKeyboardTracking(false);
1670 limit_box->setRange(2, 10000);
1672 no_limit_box_text_with_key = tr("No Hinting &Limit");
1673 no_limit_box_text = tr("No Hinting Limit");
1674 no_limit_box = new QCheckBox(no_limit_box_text);
1675 no_limit_box->setToolTip(
1676 tr("If switched on, <b>TTFautohint</b> adds no hinting limit"
1677 " to the bytecode.<br>"
1678 "For testing only."));
1681 // x height increase limit
1683 x_increase_label_text_with_key = tr("x Height In&crease Limit:");
1684 x_increase_label_text = tr("x Height Increase Limit:");
1685 x_increase_label = new QLabel(x_increase_label_text_with_key);
1686 x_increase_box = new QSpinBox;
1687 x_increase_label->setBuddy(x_increase_box);
1688 x_increase_label->setToolTip(
1689 tr("For PPEM values in the range 6&nbsp;&le; PPEM &le;&nbsp;<i>n</i>,"
1690 " where <i>n</i> is the value selected by this spin box,"
1691 " round up the font's x&nbsp;height much more often than normally.<br>"
1692 "Use this if holes in letters like <i>e</i> get filled,"
1693 " for example."));
1694 x_increase_box->setKeyboardTracking(false);
1695 x_increase_box->setRange(6, 10000);
1697 no_x_increase_box_text_with_key = tr("No x Height In&crease");
1698 no_x_increase_box_text = tr("No x Height Increase");
1699 no_x_increase_box = new QCheckBox(no_x_increase_box_text);
1700 no_x_increase_box->setToolTip(
1701 tr("If switched on,"
1702 " <b>TTFautohint</b> does not increase the x&nbsp;height."));
1705 // x height snapping exceptions
1707 snapping_label = new QLabel(tr("x Height Snapping Excep&tions:"));
1708 snapping_line = new Tooltip_Line_Edit;
1709 snapping_label->setBuddy(snapping_line);
1710 snapping_label->setToolTip(
1711 tr("<p>A list of comma separated PPEM values or value ranges"
1712 " at which no x&nbsp;height snapping shall be applied"
1713 " (x&nbsp;height snapping usually slightly increases"
1714 " the size of all glyphs).</p>"
1716 "Examples:<br>"
1717 "&nbsp;&nbsp;<tt>2, 3-5, 12-17</tt><br>"
1718 "&nbsp;&nbsp;<tt>-20, 40-</tt>"
1719 " (meaning PPEM &le; 20 or PPEM &ge; 40)<br>"
1720 "&nbsp;&nbsp;<tt>-</tt> (meaning all possible PPEM values)"));
1723 // family suffix
1725 family_suffix_label = new QLabel(tr("Family Suffix&:"));
1726 family_suffix_line = new Tooltip_Line_Edit;
1727 family_suffix_label->setBuddy(family_suffix_line);
1728 family_suffix_label->setToolTip(
1729 tr("A string that gets appended to the family name entries"
1730 " (name IDs 1, 4, 6, 16, and&nbsp;21)"
1731 " in the font's <i>name</i> table.<br>"
1732 "Mainly for testing purposes, enabling the operating system"
1733 " to display fonts simultaneously that are hinted"
1734 " with different <b>TTFautohint</b> parameters."));
1737 // fallback stem width
1739 stem_width_label_text_with_key = tr("Fallback &Stem Width:");
1740 stem_width_label_text = tr("Fallback Stem Width:");
1741 stem_width_label = new QLabel(stem_width_label_text_with_key);
1742 stem_width_box = new QSpinBox;
1743 stem_width_label->setBuddy(stem_width_box);
1744 stem_width_label->setToolTip(
1745 tr("Set horizontal stem width (in font units) for all scripts"
1746 " that lack proper standard characters in the font.<br>"
1747 "If not set, <b>TTFautohint</b> uses a hard-coded default value."));
1748 stem_width_box->setKeyboardTracking(false);
1749 stem_width_box->setRange(1, 10000);
1751 default_stem_width_box_text_with_key = tr("Default Fallback &Stem Width");
1752 default_stem_width_box_text = tr("Default Fallback Stem Width");
1753 default_stem_width_box = new QCheckBox(default_stem_width_box_text);
1754 default_stem_width_box->setToolTip(
1755 tr("If switched on, <b>TTFautohint</b> uses a default value"
1756 " for the fallback stem width (50 font units at 2048 UPEM)."));
1759 // flags
1761 wincomp_box = new QCheckBox(tr("Windows Com&patibility"));
1762 wincomp_box->setToolTip(
1763 tr("If switched on, add two artificial blue zones positioned at the"
1764 " <tt>usWinAscent</tt> and <tt>usWinDescent</tt> values"
1765 " (from the font's <i>OS/2</i> table)."
1766 " This option, usually in combination"
1767 " with value <tt>-</tt> (a single dash)"
1768 " for the <i>x&nbsp;Height Snapping Exceptions</i> option,"
1769 " should be used if those two <i>OS/2</i> values are tight,"
1770 " and you are experiencing clipping during rendering."));
1772 adjust_box = new QCheckBox(tr("Ad&just Subglyphs"));
1773 adjust_box->setToolTip(
1774 tr("If switched on, the original bytecode of the input font"
1775 " gets applied (at EM size, usually 2048ppem)"
1776 " to derive the glyph outlines for <b>TTFautohint</b>.<br>"
1777 "Use this option only if subglyphs"
1778 " are incorrectly scaled and shifted.<br>"
1779 "Note that the original bytecode will always be discarded."));
1781 hint_box = new QCheckBox(tr("Hint Co&mposites")
1782 + " "); // make label wider
1783 hint_box->setToolTip(
1784 tr("If switched on, <b>TTFautohint</b> hints composite glyphs"
1785 " as a whole, including subglyphs."
1786 " Otherwise, glyph components get hinted separately.<br>"
1787 "Deactivating this flag reduces the bytecode size enormously,"
1788 " however, it might yield worse results."));
1790 symbol_box = new QCheckBox(tr("S&ymbol Font"));
1791 symbol_box->setToolTip(
1792 tr("If switched on, <b>TTFautohint</b> accepts fonts"
1793 " that don't contain a single standard character"
1794 " for any of the supported scripts.<br>"
1795 "Use this for symbol or dingbat fonts, for example."));
1797 dehint_box = new QCheckBox(tr("&Dehint"));
1798 dehint_box->setToolTip(
1799 tr("If set, remove all hints from the font.<br>"
1800 "For testing only."));
1802 info_label = new QLabel(tr("ttf&autohint Info:"));
1803 info_box = new QComboBox;
1804 info_label->setBuddy(info_box);
1805 info_label->setToolTip(
1806 tr("Specify which information about <b>TTFautohint</b>"
1807 " and its calling parameters gets added to the version string(s)"
1808 " (name ID&nbsp;5) in the <i>name</i> table.<br>"
1809 "If you want to archive control instruction information,"
1810 " use a <i>TTFA</i> table."));
1811 info_box->insertItem(0, tr("None"));
1812 info_box->insertItem(1, tr("Version"));
1813 info_box->insertItem(2, tr("Version and Parameters"));
1815 TTFA_box = new QCheckBox(tr("Add TTFA Info Ta&ble"));
1816 TTFA_box->setToolTip(
1817 tr("If switched on, an SFNT table called <i>TTFA</i>"
1818 " gets added to the output font,"
1819 " holding a dump of all parameters."
1820 " In particular, it lists all control instructions."));
1823 // stem width and positioning
1825 stem_label = new QLabel(tr("Stron&g Stem Width&nbsp;<br>"
1826 "and Positioning:"));
1827 stem_label->setToolTip(
1828 tr("<b>TTFautohint</b> provides two different hinting algorithms"
1829 " that can be selected for various hinting modes."
1831 "<p><i>strong</i> (checkbox set):"
1832 " Position horizontal stems and snap stem widths"
1833 " to integer pixel values. While making the output look crisper,"
1834 " outlines become more distorted.</p>"
1836 "<p><i>smooth</i> (checkbox not set):"
1837 " Use discrete values for horizontal stems and stem widths."
1838 " This only slightly increases the contrast"
1839 " but avoids larger outline distortion.</p>"));
1841 gray_box = new QCheckBox(tr("Grayscale"));
1842 gray_box->setToolTip(
1843 tr("<b></b>Grayscale rendering, no ClearType activated."));
1844 stem_label->setBuddy(gray_box);
1846 gdi_box = new QCheckBox(tr("GDI ClearType"));
1847 gdi_box->setToolTip(
1848 tr("GDI ClearType rendering,"
1849 " introduced in 2000 for Windows XP.<br>"
1850 "The rasterizer version (as returned by the"
1851 " GETINFO bytecode instruction) is in the range"
1852 " 36&nbsp;&le; version &lt;&nbsp;38, and ClearType is enabled.<br>"
1853 "Along the vertical axis, this mode behaves like B/W rendering."));
1855 dw_box = new QCheckBox(tr("DW ClearType"));
1856 dw_box->setToolTip(
1857 tr("DirectWrite ClearType rendering,"
1858 " introduced in 2008 for Windows Vista.<br>"
1859 "The rasterizer version (as returned by the"
1860 " GETINFO bytecode instruction) is &ge;&nbsp;38,"
1861 " ClearType is enabled, and subpixel positioning is enabled also.<br>"
1862 "Smooth rendering along the vertical axis."));
1865 // running
1867 watch_box = new QCheckBox(tr("&Watch Input Files"));
1868 watch_box->setToolTip(
1869 tr("If switched on, <b>TTFautohint</b> automatically re-runs"
1870 " the hinting process as soon as an input file"
1871 " (either the font, the reference font,"
1872 " or the control instructions file) is modified.<br>"
1873 "Pressing the %1 button starts watching.<br>"
1874 "If an error occurs, watching stops and must be restarted"
1875 " with the %1 button.")
1876 .arg(QUOTE_STRING_LITERAL(tr("Run"))));
1878 run_button = new QPushButton(" "
1879 + tr("&Run")
1880 + " "); // make label wider
1882 if (horizontal_layout)
1883 create_horizontal_layout();
1884 else
1885 create_vertical_layout();
1889 // XXX distances are specified in pixels,
1890 // making the layout dependent on the output device resolution
1891 void
1892 Main_GUI::create_vertical_layout()
1894 // top area
1895 QGridLayout* file_layout = new QGridLayout;
1897 file_layout->addWidget(input_label, 0, 0, Qt::AlignRight);
1898 file_layout->addWidget(input_line, 0, 1);
1899 file_layout->addWidget(input_button, 0, 2);
1901 file_layout->setRowStretch(1, 1);
1903 file_layout->addWidget(output_label, 2, 0, Qt::AlignRight);
1904 file_layout->addWidget(output_line, 2, 1);
1905 file_layout->addWidget(output_button, 2, 2);
1907 file_layout->setRowStretch(3, 1);
1909 file_layout->addWidget(control_label, 4, 0, Qt::AlignRight);
1910 file_layout->addWidget(control_line, 4, 1);
1911 file_layout->addWidget(control_button, 4, 2);
1913 file_layout->setRowStretch(5, 1);
1915 file_layout->addWidget(reference_label, 6, 0, Qt::AlignRight);
1916 file_layout->addWidget(reference_line, 6, 1);
1917 file_layout->addWidget(reference_button, 6, 2);
1919 // bottom area
1920 QGridLayout* run_layout = new QGridLayout;
1922 run_layout->addWidget(watch_box, 0, 1);
1923 run_layout->addWidget(run_button, 0, 3, Qt::AlignRight);
1924 run_layout->setColumnStretch(0, 1);
1925 run_layout->setColumnStretch(2, 2);
1928 // the whole gui
1930 QGridLayout* gui_layout = new QGridLayout;
1931 QFrame* hline = new QFrame;
1932 hline->setFrameShape(QFrame::HLine);
1933 int row = 0; // this counter simplifies inserting new items
1935 gui_layout->setRowMinimumHeight(row, 10); // XXX urgh, pixels...
1936 gui_layout->setRowStretch(row++, 1);
1938 gui_layout->addLayout(file_layout, row, 0, row, -1);
1939 gui_layout->setRowStretch(row++, 1);
1941 gui_layout->addWidget(hline, row, 0, row, -1);
1942 gui_layout->setRowStretch(row++, 1);
1944 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1945 gui_layout->setRowStretch(row++, 1);
1947 gui_layout->addWidget(min_label, row, 0, Qt::AlignRight);
1948 gui_layout->addWidget(min_box, row++, 1, Qt::AlignLeft);
1949 gui_layout->addWidget(max_label, row, 0, Qt::AlignRight);
1950 gui_layout->addWidget(max_box, row++, 1, Qt::AlignLeft);
1952 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1953 gui_layout->setRowStretch(row++, 1);
1955 gui_layout->addWidget(default_label, row, 0, Qt::AlignRight);
1956 gui_layout->addWidget(default_box, row++, 1, Qt::AlignLeft);
1958 QGridLayout* fallback_layout = new QGridLayout;
1959 fallback_layout->addWidget(fallback_label, 0, 0, Qt::AlignRight);
1960 fallback_layout->addWidget(fallback_hint_or_scale_box, 0, 1, Qt::AlignLeft);
1962 gui_layout->addLayout(fallback_layout, row++, 0, Qt::AlignRight);
1963 gui_layout->addWidget(fallback_box, row++, 1, Qt::AlignLeft);
1965 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1966 gui_layout->setRowStretch(row++, 1);
1968 gui_layout->addWidget(limit_label, row, 0, Qt::AlignRight);
1969 gui_layout->addWidget(limit_box, row++, 1, Qt::AlignLeft);
1970 gui_layout->addWidget(no_limit_box, row++, 1);
1972 gui_layout->addWidget(x_increase_label, row, 0, Qt::AlignRight);
1973 gui_layout->addWidget(x_increase_box, row++, 1, Qt::AlignLeft);
1974 gui_layout->addWidget(no_x_increase_box, row++, 1);
1976 gui_layout->addWidget(snapping_label, row, 0, Qt::AlignRight);
1977 gui_layout->addWidget(snapping_line, row++, 1, Qt::AlignLeft);
1979 gui_layout->addWidget(stem_width_label, row, 0, Qt::AlignRight);
1980 gui_layout->addWidget(stem_width_box, row++, 1, Qt::AlignLeft);
1981 gui_layout->addWidget(default_stem_width_box, row++, 1);
1983 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1984 gui_layout->setRowStretch(row++, 1);
1986 gui_layout->addWidget(wincomp_box, row++, 1);
1987 gui_layout->addWidget(adjust_box, row++, 1);
1988 gui_layout->addWidget(hint_box, row++, 1);
1989 gui_layout->addWidget(symbol_box, row++, 1);
1990 gui_layout->addWidget(dehint_box, row++, 1);
1992 gui_layout->addWidget(info_label, row, 0, Qt::AlignRight);
1993 gui_layout->addWidget(info_box, row++, 1, Qt::AlignLeft);
1994 gui_layout->addWidget(TTFA_box, row++, 1);
1995 gui_layout->addWidget(family_suffix_label, row, 0, Qt::AlignRight);
1996 gui_layout->addWidget(family_suffix_line, row++, 1, Qt::AlignLeft);
1997 gui_layout->addWidget(ref_idx_label, row, 0, Qt::AlignRight);
1998 gui_layout->addWidget(ref_idx_box, row++, 1, Qt::AlignLeft);
2000 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
2001 gui_layout->setRowStretch(row++, 1);
2003 gui_layout->addWidget(stem_label, row, 0, Qt::AlignRight | Qt::AlignBottom);
2004 gui_layout->addWidget(gray_box, row++, 1, Qt::AlignBottom);
2005 gui_layout->addWidget(gdi_box, row++, 1);
2006 gui_layout->addWidget(dw_box, row++, 1);
2008 gui_layout->setRowMinimumHeight(row, 30); // XXX urgh, pixels...
2009 gui_layout->setRowStretch(row++, 1);
2011 gui_layout->addLayout(run_layout, row, 0, row, -1);
2013 // create dummy widget to register layout
2014 QWidget* main_widget = new QWidget;
2015 main_widget->setLayout(gui_layout);
2016 setCentralWidget(main_widget);
2017 setWindowTitle("TTFautohint");
2021 // XXX distances are specified in pixels,
2022 // making the layout dependent on the output device resolution
2023 void
2024 Main_GUI::create_horizontal_layout()
2026 // top area
2027 QGridLayout* file_layout = new QGridLayout;
2029 file_layout->addWidget(input_label, 0, 0, Qt::AlignRight);
2030 file_layout->addWidget(input_line, 0, 1);
2031 file_layout->addWidget(input_button, 0, 2);
2033 file_layout->setRowStretch(1, 1);
2035 file_layout->addWidget(output_label, 2, 0, Qt::AlignRight);
2036 file_layout->addWidget(output_line, 2, 1);
2037 file_layout->addWidget(output_button, 2, 2);
2039 file_layout->setRowStretch(3, 1);
2041 file_layout->addWidget(control_label, 4, 0, Qt::AlignRight);
2042 file_layout->addWidget(control_line, 4, 1);
2043 file_layout->addWidget(control_button, 4, 2);
2045 file_layout->setRowStretch(5, 1);
2047 file_layout->addWidget(reference_label, 6, 0, Qt::AlignRight);
2048 file_layout->addWidget(reference_line, 6, 1);
2049 file_layout->addWidget(reference_button, 6, 2);
2051 // bottom area
2052 QGridLayout* run_layout = new QGridLayout;
2054 run_layout->addWidget(watch_box, 0, 1);
2055 run_layout->addWidget(run_button, 0, 3, Qt::AlignRight);
2056 run_layout->setColumnStretch(0, 2);
2057 run_layout->setColumnStretch(2, 3);
2058 run_layout->setColumnStretch(4, 1);
2061 // the whole gui
2063 QGridLayout* gui_layout = new QGridLayout;
2064 QFrame* hline = new QFrame;
2065 hline->setFrameShape(QFrame::HLine);
2066 int row = 0; // this counter simplifies inserting new items
2068 // margin
2069 gui_layout->setColumnMinimumWidth(0, 10); // XXX urgh, pixels...
2070 gui_layout->setColumnStretch(0, 1);
2072 // left
2073 gui_layout->setRowMinimumHeight(row, 10); // XXX urgh, pixels...
2074 gui_layout->setRowStretch(row++, 1);
2076 gui_layout->addLayout(file_layout, row, 0, row, -1);
2077 gui_layout->setRowStretch(row++, 1);
2079 gui_layout->addWidget(hline, row, 0, row, -1);
2080 gui_layout->setRowStretch(row++, 1);
2082 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
2083 gui_layout->setRowStretch(row++, 1);
2085 gui_layout->addWidget(min_label, row, 1, Qt::AlignRight);
2086 gui_layout->addWidget(min_box, row++, 2, Qt::AlignLeft);
2087 gui_layout->addWidget(max_label, row, 1, Qt::AlignRight);
2088 gui_layout->addWidget(max_box, row++, 2, Qt::AlignLeft);
2090 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
2091 gui_layout->setRowStretch(row++, 1);
2093 gui_layout->addWidget(default_label, row, 1, Qt::AlignRight);
2094 gui_layout->addWidget(default_box, row++, 2, Qt::AlignLeft);
2096 QGridLayout* fallback_layout = new QGridLayout;
2097 fallback_layout->addWidget(fallback_label, 0, 0, Qt::AlignRight);
2098 fallback_layout->addWidget(fallback_hint_or_scale_box, 0, 1, Qt::AlignLeft);
2100 gui_layout->addLayout(fallback_layout, row, 1, Qt::AlignRight);
2101 gui_layout->addWidget(fallback_box, row++, 2, Qt::AlignLeft);
2103 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
2104 gui_layout->setRowStretch(row++, 1);
2106 gui_layout->addWidget(limit_label, row, 1, Qt::AlignRight);
2107 gui_layout->addWidget(limit_box, row++, 2, Qt::AlignLeft);
2108 gui_layout->addWidget(no_limit_box, row++, 2);
2110 gui_layout->addWidget(x_increase_label, row, 1, Qt::AlignRight);
2111 gui_layout->addWidget(x_increase_box, row++, 2, Qt::AlignLeft);
2112 gui_layout->addWidget(no_x_increase_box, row++, 2);
2114 gui_layout->addWidget(snapping_label, row, 1, Qt::AlignRight);
2115 gui_layout->addWidget(snapping_line, row++, 2, Qt::AlignLeft);
2117 gui_layout->addWidget(stem_width_label, row, 1, Qt::AlignRight);
2118 gui_layout->addWidget(stem_width_box, row++, 2, Qt::AlignLeft);
2119 gui_layout->addWidget(default_stem_width_box, row++, 2);
2121 gui_layout->setRowMinimumHeight(row, 30); // XXX urgh, pixels...
2122 gui_layout->setRowStretch(row++, 1);
2124 gui_layout->addLayout(run_layout, row, 0, row, -1);
2126 // column separator
2127 gui_layout->setColumnMinimumWidth(3, 20); // XXX urgh, pixels...
2128 gui_layout->setColumnStretch(3, 1);
2130 // right
2131 row = 4;
2132 gui_layout->addWidget(wincomp_box, row++, 4);
2133 gui_layout->addWidget(adjust_box, row++, 4);
2134 gui_layout->addWidget(hint_box, row++, 4);
2135 gui_layout->addWidget(symbol_box, row++, 4);
2136 gui_layout->addWidget(dehint_box, row++, 4);
2138 gui_layout->addWidget(info_label, row, 3, Qt::AlignRight);
2139 gui_layout->addWidget(info_box, row++, 4, Qt::AlignLeft);
2140 gui_layout->addWidget(TTFA_box, row++, 4);
2141 gui_layout->addWidget(family_suffix_label, row, 3, Qt::AlignRight);
2142 gui_layout->addWidget(family_suffix_line, row++, 4, Qt::AlignLeft);
2143 gui_layout->addWidget(ref_idx_label, row, 3, Qt::AlignRight);
2144 gui_layout->addWidget(ref_idx_box, row++, 4, Qt::AlignLeft);
2146 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
2147 gui_layout->setRowStretch(row++, 1);
2149 gui_layout->addWidget(stem_label, row, 3, Qt::AlignRight | Qt::AlignBottom);
2150 gui_layout->addWidget(gray_box, row++, 4, Qt::AlignBottom);
2151 gui_layout->addWidget(gdi_box, row++, 4);
2152 gui_layout->addWidget(dw_box, row++, 4);
2154 // margin
2155 gui_layout->setColumnMinimumWidth(5, 10); // XXX urgh, pixels...
2156 gui_layout->setColumnStretch(5, 1);
2158 // create dummy widget to register layout
2159 QWidget* main_widget = new QWidget;
2160 main_widget->setLayout(gui_layout);
2161 setCentralWidget(main_widget);
2162 setWindowTitle("TTFautohint");
2166 void
2167 Main_GUI::create_connections()
2169 connect(input_button, SIGNAL(clicked()),
2170 SLOT(browse_input()));
2171 connect(output_button, SIGNAL(clicked()),
2172 SLOT(browse_output()));
2173 connect(control_button, SIGNAL(clicked()),
2174 SLOT(browse_control()));
2175 connect(reference_button, SIGNAL(clicked()),
2176 SLOT(browse_reference()));
2178 connect(input_line, SIGNAL(textChanged(QString)),
2179 SLOT(check_run()));
2180 connect(output_line, SIGNAL(textChanged(QString)),
2181 SLOT(check_run()));
2183 connect(input_line, SIGNAL(editingFinished()),
2184 SLOT(absolute_input()));
2185 connect(output_line, SIGNAL(editingFinished()),
2186 SLOT(absolute_output()));
2187 connect(control_line, SIGNAL(editingFinished()),
2188 SLOT(absolute_control()));
2189 connect(reference_line, SIGNAL(editingFinished()),
2190 SLOT(absolute_reference()));
2192 connect(reference_line, SIGNAL(editingFinished()),
2193 SLOT(set_ref_idx_box_max()));
2195 connect(min_box, SIGNAL(valueChanged(int)),
2196 SLOT(check_min()));
2197 connect(max_box, SIGNAL(valueChanged(int)),
2198 SLOT(check_max()));
2200 connect(limit_box, SIGNAL(valueChanged(int)),
2201 SLOT(check_limit()));
2202 connect(no_limit_box, SIGNAL(clicked()),
2203 SLOT(check_no_limit()));
2205 connect(no_x_increase_box, SIGNAL(clicked()),
2206 SLOT(check_no_x_increase()));
2208 connect(snapping_line, SIGNAL(editingFinished()),
2209 SLOT(check_number_set()));
2210 connect(snapping_line, SIGNAL(textEdited(QString)),
2211 SLOT(clear_status_bar()));
2213 connect(family_suffix_line, SIGNAL(editingFinished()),
2214 SLOT(check_family_suffix()));
2215 connect(family_suffix_line, SIGNAL(textEdited(QString)),
2216 SLOT(clear_status_bar()));
2218 connect(default_stem_width_box, SIGNAL(clicked()),
2219 SLOT(check_default_stem_width()));
2221 connect(dehint_box, SIGNAL(clicked()),
2222 SLOT(check_dehint()));
2224 connect(file_watcher, SIGNAL(fileChanged(const QString&)),
2225 SLOT(start_timer()));
2226 connect(timer, SIGNAL(timeout()),
2227 SLOT(watch_files()));
2229 connect(watch_box, SIGNAL(clicked()),
2230 SLOT(check_watch()));
2232 connect(run_button, SIGNAL(clicked()),
2233 SLOT(run()));
2237 void
2238 Main_GUI::create_actions()
2240 exit_act = new QAction(tr("E&xit"), this);
2241 exit_act->setShortcuts(QKeySequence::Quit);
2242 connect(exit_act, SIGNAL(triggered()), SLOT(close()));
2244 about_act = new QAction(tr("&About"), this);
2245 connect(about_act, SIGNAL(triggered()), SLOT(about()));
2247 about_Qt_act = new QAction(tr("About &Qt"), this);
2248 connect(about_Qt_act, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
2252 void
2253 Main_GUI::create_menus()
2255 file_menu = menuBar()->addMenu(tr("&File"));
2256 file_menu->addAction(exit_act);
2258 help_menu = menuBar()->addMenu(tr("&Help"));
2259 help_menu->addAction(about_act);
2260 help_menu->addAction(about_Qt_act);
2264 void
2265 Main_GUI::create_status_bar()
2267 statusBar()->showMessage("");
2271 void
2272 Main_GUI::set_defaults()
2274 min_box->setValue(hinting_range_min);
2275 max_box->setValue(hinting_range_max);
2277 default_box->setCurrentIndex(default_script_idx);
2278 fallback_hint_or_scale_box->setCurrentIndex(fallback_scaling);
2279 fallback_box->setCurrentIndex(fallback_script_idx);
2281 limit_box->setValue(hinting_limit ? hinting_limit : hinting_range_max);
2282 // handle command line option `--hinting-limit=0'
2283 if (!hinting_limit)
2285 hinting_limit = max_box->value();
2286 no_limit_box->setChecked(true);
2289 x_increase_box->setValue(increase_x_height ? increase_x_height
2290 : TA_INCREASE_X_HEIGHT);
2291 // handle command line option `--increase-x-height=0'
2292 if (!increase_x_height)
2294 increase_x_height = TA_INCREASE_X_HEIGHT;
2295 no_x_increase_box->setChecked(true);
2298 snapping_line->setText(x_height_snapping_exceptions_string);
2299 family_suffix_line->setText(family_suffix);
2301 if (fallback_stem_width)
2302 stem_width_box->setValue(fallback_stem_width);
2303 else
2305 stem_width_box->setValue(50);
2306 default_stem_width_box->setChecked(true);
2309 if (windows_compatibility)
2310 wincomp_box->setChecked(true);
2311 if (adjust_subglyphs)
2312 adjust_box->setChecked(true);
2313 if (hint_composites)
2314 hint_box->setChecked(true);
2315 if (symbol)
2316 symbol_box->setChecked(true);
2317 if (dehint)
2318 dehint_box->setChecked(true);
2319 if (no_info)
2320 info_box->setCurrentIndex(0);
2321 else if (detailed_info)
2322 info_box->setCurrentIndex(2);
2323 else
2324 info_box->setCurrentIndex(1);
2325 if (TTFA_info)
2326 TTFA_box->setChecked(true);
2328 if (gray_strong_stem_width)
2329 gray_box->setChecked(true);
2330 if (gdi_cleartype_strong_stem_width)
2331 gdi_box->setChecked(true);
2332 if (dw_cleartype_strong_stem_width)
2333 dw_box->setChecked(true);
2335 run_button->setEnabled(false);
2337 check_min();
2338 check_max();
2339 check_limit();
2341 check_no_limit();
2342 check_no_x_increase();
2343 check_number_set();
2345 check_watch();
2347 // do this last since it disables almost everything
2348 check_dehint();
2352 void
2353 Main_GUI::read_settings()
2355 QSettings settings;
2356 // QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
2357 // QSize size = settings.value("size", QSize(400, 400)).toSize();
2358 // resize(size);
2359 // move(pos);
2363 void
2364 Main_GUI::write_settings()
2366 QSettings settings;
2367 // settings.setValue("pos", pos());
2368 // settings.setValue("size", size());
2371 // end of maingui.cpp