[gui] Show tooltip for overlong x height exception string.
[ttfautohint.git] / frontend / maingui.cpp
blobdcfb58c57b5d0e44fc3bcb02fdd13fcd1dea94b0
1 // maingui.cpp
3 // Copyright (C) 2012 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>
20 #include <QtGui>
22 #include "info.h"
23 #include "maingui.h"
25 #include <ttfautohint.h>
28 // XXX Qt 4.8 bug: locale->quoteString("foo")
29 // inserts wrongly encoded quote characters
30 // into rich text QString
31 #if HAVE_QT_QUOTESTRING
32 # define QUOTE_STRING(x) locale->quoteString(x)
33 # define QUOTE_STRING_LITERAL(x) locale->quoteString(x)
34 #else
35 # define QUOTE_STRING(x) "\"" + x + "\""
36 # define QUOTE_STRING_LITERAL(x) "\"" x "\""
37 #endif
40 Main_GUI::Main_GUI(int range_min,
41 int range_max,
42 int limit,
43 bool gray,
44 bool gdi,
45 bool dw,
46 int increase,
47 const char* exceptions,
48 bool ignore,
49 bool wincomp,
50 bool pre,
51 bool components,
52 bool no,
53 int fallback,
54 bool symb)
55 : hinting_range_min(range_min),
56 hinting_range_max(range_max),
57 hinting_limit(limit),
58 gray_strong_stem_width(gray),
59 gdi_cleartype_strong_stem_width(gdi),
60 dw_cleartype_strong_stem_width(dw),
61 increase_x_height(increase),
62 x_height_snapping_exceptions_string(exceptions),
63 ignore_restrictions(ignore),
64 windows_compatibility(wincomp),
65 pre_hinting(pre),
66 hint_with_components(components),
67 no_info(no),
68 latin_fallback(fallback),
69 symbol(symb)
71 x_height_snapping_exceptions = NULL;
73 create_layout();
74 create_connections();
75 create_actions();
76 create_menus();
77 create_status_bar();
79 set_defaults();
80 read_settings();
82 setUnifiedTitleAndToolBarOnMac(true);
84 // XXX register translations somewhere and loop over them
85 if (QLocale::system().name() == "en_US")
86 locale = new QLocale;
87 else
88 locale = new QLocale(QLocale::C);
92 Main_GUI::~Main_GUI()
94 number_set_free(x_height_snapping_exceptions);
98 // overloading
100 void
101 Main_GUI::closeEvent(QCloseEvent* event)
103 write_settings();
104 event->accept();
108 void
109 Main_GUI::about()
111 QMessageBox::about(this,
112 tr("About TTFautohint"),
113 tr("<p>This is <b>TTFautohint</b> version %1<br>"
114 " Copyright %2 2011-2012<br>"
115 " by Werner Lemberg <tt>&lt;wl@gnu.org&gt;</tt></p>"
117 "<p><b>TTFautohint</b> adds new auto-generated hints"
118 " to a TrueType font or TrueType collection.</p>"
120 "<p>License:"
121 " <a href='http://www.freetype.org/FTL.TXT'>FreeType"
122 " License (FTL)</a> or"
123 " <a href='http://www.freetype.org/GPL.TXT'>GNU"
124 " GPLv2</a></p>")
125 .arg(VERSION)
126 .arg(QChar(0xA9)));
130 void
131 Main_GUI::browse_input()
133 // XXX remember last directory
134 QString file = QFileDialog::getOpenFileName(
135 this,
136 tr("Open Input File"),
137 QDir::homePath(),
138 "");
139 if (!file.isEmpty())
140 input_line->setText(QDir::toNativeSeparators(file));
144 void
145 Main_GUI::browse_output()
147 // XXX remember last directory
148 QString file = QFileDialog::getSaveFileName(
149 this,
150 tr("Open Output File"),
151 QDir::homePath(),
152 "");
154 if (!file.isEmpty())
155 output_line->setText(QDir::toNativeSeparators(file));
159 void
160 Main_GUI::check_min()
162 int min = min_box->value();
163 int max = max_box->value();
164 int limit = limit_box->value();
165 if (min > max)
166 max_box->setValue(min);
167 if (min > limit)
168 limit_box->setValue(min);
172 void
173 Main_GUI::check_max()
175 int min = min_box->value();
176 int max = max_box->value();
177 int limit = limit_box->value();
178 if (max < min)
179 min_box->setValue(max);
180 if (max > limit)
181 limit_box->setValue(max);
185 void
186 Main_GUI::check_limit()
188 int min = min_box->value();
189 int max = max_box->value();
190 int limit = limit_box->value();
191 if (limit < max)
192 max_box->setValue(limit);
193 if (limit < min)
194 min_box->setValue(limit);
198 void
199 Main_GUI::check_no_limit()
201 if (no_limit_box->isChecked())
203 limit_label->setEnabled(false);
204 limit_box->setEnabled(false);
206 else
208 limit_label->setEnabled(true);
209 limit_box->setEnabled(true);
214 void
215 Main_GUI::check_no_increase()
217 if (no_increase_box->isChecked())
219 increase_label->setEnabled(false);
220 increase_box->setEnabled(false);
222 else
224 increase_label->setEnabled(true);
225 increase_box->setEnabled(true);
230 void
231 Main_GUI::check_run()
233 if (input_line->text().isEmpty() || output_line->text().isEmpty())
234 run_button->setEnabled(false);
235 else
236 run_button->setEnabled(true);
240 void
241 Main_GUI::absolute_input()
243 QString input_name = QDir::fromNativeSeparators(input_line->text());
244 if (!input_name.isEmpty()
245 && QDir::isRelativePath(input_name))
247 QDir cur_path(QDir::currentPath() + "/" + input_name);
248 input_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
253 void
254 Main_GUI::absolute_output()
256 QString output_name = QDir::fromNativeSeparators(output_line->text());
257 if (!output_name.isEmpty()
258 && QDir::isRelativePath(output_name))
260 QDir cur_path(QDir::currentPath() + "/" + output_name);
261 output_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
266 void
267 Main_GUI::check_number_set()
269 QString text = snapping_line->text();
270 QString qs;
272 // construct ASCII string from arbitrary Unicode data;
273 // the idea is to accept, say, CJK fullwidth digits also
274 for (int i = 0; i < text.size(); i++)
276 QChar c = text.at(i);
278 int digit = c.digitValue();
279 if (digit >= 0)
280 qs += QString::number(digit);
281 else if (c.isSpace())
282 qs += ' ';
283 // U+30FC KATAGANA-HIRAGANA PROLONGED SOUND MARK is assigned
284 // to the `-' key in some Japanese input methods
285 else if (c.category() == QChar::Punctuation_Dash
286 || c == QChar(0x30FC))
287 qs += '-';
288 // various Unicode COMMA characters,
289 // including representation forms
290 else if (c == QChar(',')
291 || c == QChar(0x055D)
292 || c == QChar(0x060C)
293 || c == QChar(0x07F8)
294 || c == QChar(0x1363)
295 || c == QChar(0x1802)
296 || c == QChar(0x1808)
297 || c == QChar(0x3001)
298 || c == QChar(0xA4FE)
299 || c == QChar(0xA60D)
300 || c == QChar(0xA6F5)
301 || c == QChar(0xFE10)
302 || c == QChar(0xFE11)
303 || c == QChar(0xFE50)
304 || c == QChar(0xFE51)
305 || c == QChar(0xFF0C)
306 || c == QChar(0xFF64))
307 qs += ',';
308 else
309 qs += c; // we do error handling below
312 if (x_height_snapping_exceptions)
313 number_set_free(x_height_snapping_exceptions);
315 QByteArray str = qs.toLocal8Bit();
316 const char* s = number_set_parse(str.constData(),
317 &x_height_snapping_exceptions,
318 6, 0x7FFF);
319 if (s && *s)
321 statusBar()->setStyleSheet("color: red;");
322 if (x_height_snapping_exceptions == NUMBERSET_ALLOCATION_ERROR)
323 statusBar()->showMessage(
324 tr("allocation error"));
325 else if (x_height_snapping_exceptions == NUMBERSET_INVALID_CHARACTER)
326 statusBar()->showMessage(
327 tr("invalid character (use digits, dashes, commas, and spaces)"));
328 else if (x_height_snapping_exceptions == NUMBERSET_OVERFLOW)
329 statusBar()->showMessage(
330 tr("overflow"));
331 else if (x_height_snapping_exceptions == NUMBERSET_INVALID_RANGE)
332 statusBar()->showMessage(
333 tr("invalid range (minimum is 6, maximum is 32767)"));
334 else if (x_height_snapping_exceptions == NUMBERSET_OVERLAPPING_RANGES)
335 statusBar()->showMessage(
336 tr("overlapping ranges"));
337 else if (x_height_snapping_exceptions == NUMBERSET_NOT_ASCENDING)
338 statusBar()->showMessage(
339 tr("values und ranges must be specified in ascending order"));
341 snapping_line->setText(qs);
342 snapping_line->setFocus(Qt::OtherFocusReason);
343 snapping_line->setCursorPosition(s - str.constData());
345 x_height_snapping_exceptions = NULL;
347 else
349 // normalize if there is no error
350 char* new_str = number_set_show(x_height_snapping_exceptions,
351 6, 0x7FFF);
352 snapping_line->setText(new_str);
353 free(new_str);
358 void
359 Main_GUI::clear_status_bar()
361 statusBar()->clearMessage();
362 statusBar()->setStyleSheet("");
367 Main_GUI::check_filenames(const QString& input_name,
368 const QString& output_name)
370 if (!QFile::exists(input_name))
372 QMessageBox::warning(
373 this,
374 "TTFautohint",
375 tr("The file %1 cannot be found.")
376 .arg(QUOTE_STRING(QDir::toNativeSeparators(input_name))),
377 QMessageBox::Ok,
378 QMessageBox::Ok);
379 return 0;
382 if (input_name == output_name)
384 QMessageBox::warning(
385 this,
386 "TTFautohint",
387 tr("Input and output file names must be different."),
388 QMessageBox::Ok,
389 QMessageBox::Ok);
390 return 0;
393 if (QFile::exists(output_name))
395 int ret = QMessageBox::warning(
396 this,
397 "TTFautohint",
398 tr("The file %1 already exists.\n"
399 "Overwrite?")
400 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name))),
401 QMessageBox::Yes | QMessageBox::No,
402 QMessageBox::No);
403 if (ret == QMessageBox::No)
404 return 0;
407 return 1;
412 Main_GUI::open_files(const QString& input_name,
413 FILE** in,
414 const QString& output_name,
415 FILE** out)
417 const int buf_len = 1024;
418 char buf[buf_len];
420 *in = fopen(qPrintable(input_name), "rb");
421 if (!*in)
423 strerror_r(errno, buf, buf_len);
424 QMessageBox::warning(
425 this,
426 "TTFautohint",
427 tr("The following error occurred while opening input file %1:\n")
428 .arg(QUOTE_STRING(QDir::toNativeSeparators(input_name)))
429 + QString::fromLocal8Bit(buf),
430 QMessageBox::Ok,
431 QMessageBox::Ok);
432 return 0;
435 *out = fopen(qPrintable(output_name), "wb");
436 if (!*out)
438 strerror_r(errno, buf, buf_len);
439 QMessageBox::warning(
440 this,
441 "TTFautohint",
442 tr("The following error occurred while opening output file %1:\n")
443 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name)))
444 + QString::fromLocal8Bit(buf),
445 QMessageBox::Ok,
446 QMessageBox::Ok);
447 return 0;
450 return 1;
454 extern "C" {
456 struct GUI_Progress_Data
458 long last_sfnt;
459 bool begin;
460 QProgressDialog* dialog;
465 gui_progress(long curr_idx,
466 long num_glyphs,
467 long curr_sfnt,
468 long num_sfnts,
469 void* user)
471 GUI_Progress_Data* data = (GUI_Progress_Data*)user;
473 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
475 data->dialog->setLabelText(QCoreApplication::translate(
476 "GuiProgress",
477 "Auto-hinting subfont %1 of %2"
478 " with %3 glyphs...")
479 .arg(curr_sfnt + 1)
480 .arg(num_sfnts)
481 .arg(num_glyphs));
483 if (curr_sfnt + 1 == num_sfnts)
485 data->dialog->setAutoReset(true);
486 data->dialog->setAutoClose(true);
488 else
490 data->dialog->setAutoReset(false);
491 data->dialog->setAutoClose(false);
494 data->last_sfnt = curr_sfnt;
495 data->begin = true;
498 if (data->begin)
500 if (num_sfnts == 1)
501 data->dialog->setLabelText(QCoreApplication::translate(
502 "GuiProgress",
503 "Auto-hinting %1 glyphs...")
504 .arg(num_glyphs));
505 data->dialog->setMaximum(num_glyphs - 1);
507 data->begin = false;
510 data->dialog->setValue(curr_idx);
512 if (data->dialog->wasCanceled())
513 return 1;
515 return 0;
518 } // extern "C"
521 // return value 1 indicates a retry
524 Main_GUI::handle_error(TA_Error error,
525 const unsigned char* error_string,
526 QString output_name)
528 int ret = 0;
530 if (error == TA_Err_Canceled)
532 else if (error == TA_Err_Invalid_FreeType_Version)
533 QMessageBox::critical(
534 this,
535 "TTFautohint",
536 tr("FreeType version 2.4.5 or higher is needed.\n"
537 "Are you perhaps using a wrong FreeType DLL?"),
538 QMessageBox::Ok,
539 QMessageBox::Ok);
540 else if (error == TA_Err_Invalid_Font_Type)
541 QMessageBox::warning(
542 this,
543 "TTFautohint",
544 tr("This font is not a valid font"
545 " in SFNT format with TrueType outlines.\n"
546 "In particular, CFF outlines are not supported."),
547 QMessageBox::Ok,
548 QMessageBox::Ok);
549 else if (error == TA_Err_Already_Processed)
550 QMessageBox::warning(
551 this,
552 "TTFautohint",
553 tr("This font has already been processed by TTFautohint."),
554 QMessageBox::Ok,
555 QMessageBox::Ok);
556 else if (error == TA_Err_Missing_Legal_Permission)
558 int yesno = QMessageBox::warning(
559 this,
560 "TTFautohint",
561 tr("Bit 1 in the %1 field of the %2 table is set:"
562 " This font must not be modified"
563 " without permission of the legal owner.\n"
564 "Do you have such a permission?")
565 .arg(QUOTE_STRING_LITERAL("fsType"))
566 .arg(QUOTE_STRING_LITERAL("OS/2")),
567 QMessageBox::Yes | QMessageBox::No,
568 QMessageBox::No);
569 if (yesno == QMessageBox::Yes)
571 ignore_restrictions = true;
572 ret = 1;
575 else if (error == TA_Err_Missing_Unicode_CMap)
576 QMessageBox::warning(
577 this,
578 "TTFautohint",
579 tr("No Unicode character map."),
580 QMessageBox::Ok,
581 QMessageBox::Ok);
582 else if (error == TA_Err_Missing_Symbol_CMap)
583 QMessageBox::warning(
584 this,
585 "TTFautohint",
586 tr("No symbol character map."),
587 QMessageBox::Ok,
588 QMessageBox::Ok);
589 else if (error == TA_Err_Missing_Glyph)
590 QMessageBox::warning(
591 this,
592 "TTFautohint",
593 tr("No glyph for the key character"
594 " to derive standard stem width and height.\n"
595 "For the latin script, this key character is %1 (U+006F).\n"
596 "\n"
597 "Set the %2 checkbox if you want to circumvent this test.")
598 .arg(QUOTE_STRING_LITERAL("o"))
599 .arg(QUOTE_STRING_LITERAL("symbol")),
600 QMessageBox::Ok,
601 QMessageBox::Ok);
602 else
603 QMessageBox::warning(
604 this,
605 "TTFautohint",
606 tr("Error code 0x%1 while autohinting font:\n")
607 .arg(error, 2, 16, QLatin1Char('0'))
608 + QString::fromLocal8Bit((const char*)error_string),
609 QMessageBox::Ok,
610 QMessageBox::Ok);
612 if (QFile::exists(output_name) && remove(qPrintable(output_name)))
614 const int buf_len = 1024;
615 char buf[buf_len];
617 strerror_r(errno, buf, buf_len);
618 QMessageBox::warning(
619 this,
620 "TTFautohint",
621 tr("The following error occurred while removing output file %1:\n")
622 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name)))
623 + QString::fromLocal8Bit(buf),
624 QMessageBox::Ok,
625 QMessageBox::Ok);
628 return ret;
632 void
633 Main_GUI::run()
635 statusBar()->clearMessage();
637 QString input_name = QDir::fromNativeSeparators(input_line->text());
638 QString output_name = QDir::fromNativeSeparators(output_line->text());
639 if (!check_filenames(input_name, output_name))
640 return;
642 // we need C file descriptors for communication with TTF_autohint
643 FILE* input;
644 FILE* output;
646 again:
647 if (!open_files(input_name, &input, output_name, &output))
648 return;
650 QProgressDialog dialog;
651 dialog.setCancelButtonText(tr("Cancel"));
652 dialog.setMinimumDuration(1000);
653 dialog.setWindowModality(Qt::WindowModal);
655 const unsigned char* error_string;
656 TA_Info_Func info_func = info;
657 GUI_Progress_Data gui_progress_data = {-1, true, &dialog};
658 Info_Data info_data;
660 info_data.data = NULL; // must be deallocated after use
661 info_data.data_wide = NULL; // must be deallocated after use
662 info_data.data_len = 0;
663 info_data.data_wide_len = 0;
665 info_data.hinting_range_min = min_box->value();
666 info_data.hinting_range_max = max_box->value();
667 info_data.hinting_limit = no_limit_box->isChecked()
669 : limit_box->value();
671 info_data.gray_strong_stem_width = gray_box->isChecked();
672 info_data.gdi_cleartype_strong_stem_width = gdi_box->isChecked();
673 info_data.dw_cleartype_strong_stem_width = dw_box->isChecked();
675 info_data.increase_x_height = no_increase_box->isChecked()
677 : increase_box->value();
678 info_data.x_height_snapping_exceptions = x_height_snapping_exceptions;
680 info_data.windows_compatibility = wincomp_box->isChecked();
681 info_data.pre_hinting = pre_box->isChecked();
682 info_data.hint_with_components = hint_box->isChecked();
683 info_data.latin_fallback = fallback_box->currentIndex();
684 info_data.symbol = symbol_box->isChecked();
686 if (info_box->isChecked())
688 int ret = build_version_string(&info_data);
689 if (ret == 1)
690 QMessageBox::information(
691 this,
692 "TTFautohint",
693 tr("Can't allocate memory for <b>TTFautohint</b> options string"
694 " in <i>name</i> table."),
695 QMessageBox::Ok,
696 QMessageBox::Ok);
697 else if (ret == 2)
698 QMessageBox::information(
699 this,
700 "TTFautohint",
701 tr("<b>TTFautohint</b> options string"
702 " in <i>name</i> table too long."),
703 QMessageBox::Ok,
704 QMessageBox::Ok);
706 else
707 info_func = NULL;
709 QByteArray snapping_string = snapping_line->text().toLocal8Bit();
711 TA_Error error =
712 TTF_autohint("in-file, out-file,"
713 "hinting-range-min, hinting-range-max,"
714 "hinting-limit,"
715 "gray-strong-stem-width,"
716 "gdi-cleartype-strong-stem-width,"
717 "dw-cleartype-strong-stem-width,"
718 "error-string,"
719 "progress-callback, progress-callback-data,"
720 "info-callback, info-callback-data,"
721 "ignore-restrictions,"
722 "windows-compatibility,"
723 "pre-hinting,"
724 "hint-with-components,"
725 "increase-x-height,"
726 "x-height-snapping-exceptions,"
727 "fallback-script, symbol",
728 input, output,
729 info_data.hinting_range_min, info_data.hinting_range_max,
730 info_data.hinting_limit,
731 info_data.gray_strong_stem_width,
732 info_data.gdi_cleartype_strong_stem_width,
733 info_data.dw_cleartype_strong_stem_width,
734 &error_string,
735 gui_progress, &gui_progress_data,
736 info_func, &info_data,
737 ignore_restrictions,
738 info_data.windows_compatibility,
739 info_data.pre_hinting,
740 info_data.hint_with_components,
741 info_data.increase_x_height,
742 snapping_string.constData(),
743 info_data.latin_fallback, info_data.symbol);
745 if (info_box->isChecked())
747 free(info_data.data);
748 free(info_data.data_wide);
751 fclose(input);
752 fclose(output);
754 if (error)
756 if (handle_error(error, error_string, output_name))
757 goto again;
759 else
760 statusBar()->showMessage(tr("Auto-hinting finished."));
764 // XXX distances are specified in pixels,
765 // making the layout dependent on the output device resolution
766 void
767 Main_GUI::create_layout()
770 // file stuff
772 QCompleter* completer = new QCompleter(this);
773 QFileSystemModel* model = new QFileSystemModel(completer);
774 model->setRootPath(QDir::rootPath());
775 completer->setModel(model);
777 QLabel* input_label = new QLabel(tr("&Input File:"));
778 input_line = new Drag_Drop_Line_Edit;
779 input_button = new QPushButton(tr("Browse..."));
780 input_label->setBuddy(input_line);
781 // enforce rich text to get nice word wrapping
782 input_label->setToolTip(
783 tr("<b></b>The input file, either a TrueType font (TTF),"
784 " TrueType collection (TTC), or a TrueType-based OpenType font."));
785 input_line->setCompleter(completer);
787 QLabel* output_label = new QLabel(tr("&Output File:"));
788 output_line = new Drag_Drop_Line_Edit;
789 output_button = new QPushButton(tr("Browse..."));
790 output_label->setBuddy(output_line);
791 output_label->setToolTip(
792 tr("<b></b>The output file, which will be essentially identical"
793 " to the input font but will contain new, generated hints."));
794 output_line->setCompleter(completer);
796 // layout
797 QGridLayout* file_layout = new QGridLayout;
799 file_layout->addWidget(input_label, 0, 0, Qt::AlignRight);
800 file_layout->addWidget(input_line, 0, 1);
801 file_layout->addWidget(input_button, 0, 2);
803 file_layout->setRowStretch(1, 1);
805 file_layout->addWidget(output_label, 2, 0, Qt::AlignRight);
806 file_layout->addWidget(output_line, 2, 1);
807 file_layout->addWidget(output_button, 2, 2);
810 // minmax controls
812 QLabel* min_label = new QLabel(tr("Hint Set Range Mi&nimum:"));
813 min_box = new QSpinBox;
814 min_label->setBuddy(min_box);
815 min_label->setToolTip(
816 tr("The minimum PPEM value of the range for which"
817 " <b>TTFautohint</b> computes <i>hint sets</i>."
818 " A hint set for a given PPEM value hints this size optimally."
819 " The larger the range, the more hint sets are considered,"
820 " usually increasing the size of the bytecode.<br>"
821 "Note that changing this range doesn't influence"
822 " the <i>gasp</i> table:"
823 " Hinting is enabled for all sizes."));
824 min_box->setKeyboardTracking(false);
825 min_box->setRange(2, 10000);
827 QLabel* max_label = new QLabel(tr("Hint Set Range Ma&ximum:"));
828 max_box = new QSpinBox;
829 max_label->setBuddy(max_box);
830 max_label->setToolTip(
831 tr("The maximum PPEM value of the range for which"
832 " <b>TTFautohint</b> computes <i>hint sets</i>."
833 " A hint set for a given PPEM value hints this size optimally."
834 " The larger the range, the more hint sets are considered,"
835 " usually increasing the size of the bytecode.<br>"
836 "Note that changing this range doesn't influence"
837 " the <i>gasp</i> table:"
838 " Hinting is enabled for all sizes."));
839 max_box->setKeyboardTracking(false);
840 max_box->setRange(2, 10000);
843 // hinting and fallback controls
845 QLabel* fallback_label = new QLabel(tr("Fallback &Script:"));
846 fallback_box = new QComboBox;
847 fallback_label->setBuddy(fallback_box);
848 fallback_label->setToolTip(
849 tr("This sets the fallback script module for glyphs"
850 " which <b>TTFautohint</b> can't map to a script automatically."));
851 fallback_box->insertItem(0, tr("None"));
852 fallback_box->insertItem(1, tr("Latin"));
855 // hinting limit
857 limit_label = new QLabel(tr("Hinting &Limit:"));
858 limit_box = new QSpinBox;
859 limit_label->setBuddy(limit_box);
860 limit_label->setToolTip(
861 tr("Make <b>TTFautohint</b> add bytecode to the output font so that"
862 " sizes larger than this PPEM value are not hinted"
863 " (regardless of the values in the <i>gasp</i> table)."));
864 limit_box->setKeyboardTracking(false);
865 limit_box->setRange(2, 10000);
867 no_limit_box = new QCheckBox(tr("No Hinting Limit"), this);
868 no_limit_box->setToolTip(
869 tr("If switched on, <b>TTFautohint</b> adds no hinting limit"
870 " to the bytecode."));
873 // x height increase limit
875 increase_label = new QLabel(tr("x Height In&crease Limit:"));
876 increase_box = new QSpinBox;
877 increase_label->setBuddy(increase_box);
878 increase_label->setToolTip(
879 tr("For PPEM values in the range 5&nbsp;&lt; PPEM &lt;&nbsp;<i>n</i>,"
880 " where <i>n</i> is the value selected by this spin box,"
881 " round up the font's x&nbsp;height much more often than normally.<br>"
882 "Use this if holes in letters like <i>e</i> get filled,"
883 " for example."));
884 increase_box->setKeyboardTracking(false);
885 increase_box->setRange(6, 10000);
887 no_increase_box = new QCheckBox(tr("No x Height Increase"), this);
888 no_increase_box->setToolTip(
889 tr("If switched on,"
890 " <b>TTFautohint</b> does not increase the x&nbsp;height."));
893 // x height snapping exceptions
895 QLabel* snapping_label = new QLabel(tr("x Height Snapping Excep&tions:"));
896 snapping_line = new Tooltip_Line_Edit;
897 snapping_label->setBuddy(snapping_line);
898 snapping_label->setToolTip(
899 tr("<p>A list of comma separated PPEM values or value ranges"
900 " at which no x&nbsp;height snapping shall be applied"
901 " (x&nbsp;height snapping usually slightly increases"
902 " the size of all glyphs).</p>"
904 "Examples:<br>"
905 "&nbsp;&nbsp;<tt>2, 3-5, 12-17</tt><br>"
906 "&nbsp;&nbsp;<tt>-20, 40-</tt>"
907 " (meaning PPEM &le; 20 or PPEM &ge; 40)<br>"
908 "&nbsp;&nbsp;<tt>-</tt> (meaning all possible PPEM values)"));
911 // flags
913 wincomp_box = new QCheckBox(tr("Windows Com&patibility"), this);
914 wincomp_box->setToolTip(
915 tr("If switched on, add two artificial blue zones positioned at the"
916 " <tt>usWinAscent</tt> and <tt>usWinDescent</tt> values"
917 " (from the font's <i>OS/2</i> table)."
918 " This option, usually in combination"
919 " with value <tt>-</tt> (a single dash)"
920 " for the <i>x&nbsp;Height Snapping Exceptions</i> option,"
921 " should be used if those two <i>OS/2</i> values are tight,"
922 " and you are experiencing clipping during rendering."));
924 pre_box = new QCheckBox(tr("Pr&e-hinting"), this);
925 pre_box->setToolTip(
926 tr("If switched on, the original bytecode of the input font"
927 " gets applied before <b>TTFautohint</b> starts processing"
928 " the outlines of the glyphs."));
930 hint_box = new QCheckBox(tr("Hint With Co&mponents")
931 + " ", this); // make label wider
932 hint_box->setToolTip(
933 tr("If switched on, <b>TTFautohint</b> hints composite glyphs"
934 " as a whole, including subglyphs."
935 " Otherwise, glyph components get hinted separately.<br>"
936 "Deactivating this flag reduces the bytecode size enormously,"
937 " however, it might yield worse results."));
939 symbol_box = new QCheckBox(tr("S&ymbol Font"), this);
940 symbol_box->setToolTip(
941 tr("If switched on, <b>TTFautohint</b> uses default values"
942 " for standard stem width and height"
943 " instead of deriving these values from the input font.<br>"
944 "Use this for fonts which don't contain glyphs"
945 " of a (supported) script."));
947 info_box = new QCheckBox(tr("Add ttf&autohint Info"), this);
948 info_box->setToolTip(
949 tr("If switched on, information about <b>TTFautohint</b>"
950 " and its calling parameters are added to the version string(s)"
951 " (name ID&nbsp;5) in the <i>name</i> table."));
954 // stem width and positioning
956 QLabel* stem_label = new QLabel(tr("Strong Stem &Width and Positioning:"));
957 stem_label->setToolTip(
958 tr("<b>TTFautohint</b> provides two different hinting algorithms"
959 " which can be selected for various hinting modes."
961 "<p><i>strong:</i> Position horizontal stems and snap stem widths"
962 " to integer pixel values. While making the output look crisper,"
963 " outlines become more distorted.</p>"
965 "<p><i>smooth:</i> Use discrete values for horizontal stems"
966 " and stem widths. This only slightly increases the contrast"
967 " but avoids larger outline distortion.</p>"));
969 gray_box = new QCheckBox(tr("Grayscale"), this);
970 gray_box->setToolTip(
971 tr("<b></b>Grayscale rendering, no ClearType activated."));
972 stem_label->setBuddy(gray_box);
974 gdi_box = new QCheckBox(tr("GDI ClearType"), this);
975 gdi_box->setToolTip(
976 tr("GDI ClearType rendering,"
977 " introduced in 2000 for Windows XP.<br>"
978 "The rasterizer version (as returned by the"
979 " GETINFO bytecode instruction) is in the range"
980 " 36&nbsp;&le; version &lt;&nbsp;38, and ClearType is enabled.<br>"
981 "Along the vertical axis, this mode behaves like B/W rendering."));
983 dw_box = new QCheckBox(tr("DW ClearType"), this);
984 dw_box->setToolTip(
985 tr("DirectWrite ClearType rendering,"
986 " introduced in 2008 for Windows Vista.<br>"
987 "The rasterizer version (as returned by the"
988 " GETINFO bytecode instruction) is &ge;&nbsp;38,"
989 " ClearType is enabled, and subpixel positioning is enabled also.<br>"
990 "Smooth rendering along the vertical axis."));
993 // running
995 run_button = new QPushButton(" "
996 + tr("&Run")
997 + " "); // make label wider
1000 // the whole gui
1002 QGridLayout* gui_layout = new QGridLayout;
1003 QFrame* hline = new QFrame;
1004 hline->setFrameShape(QFrame::HLine);
1005 int row = 0; // this counter simplifies inserting new items
1007 gui_layout->setRowMinimumHeight(row, 10); // XXX urgh, pixels...
1008 gui_layout->setRowStretch(row++, 1);
1010 gui_layout->addLayout(file_layout, row, 0, row, -1);
1011 gui_layout->setRowStretch(row++, 1);
1013 gui_layout->addWidget(hline, row, 0, row, -1);
1014 gui_layout->setRowStretch(row++, 1);
1016 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1017 gui_layout->setRowStretch(row++, 1);
1019 gui_layout->addWidget(min_label, row, 0, Qt::AlignRight);
1020 gui_layout->addWidget(min_box, row++, 1, Qt::AlignLeft);
1021 gui_layout->addWidget(max_label, row, 0, Qt::AlignRight);
1022 gui_layout->addWidget(max_box, row++, 1, Qt::AlignLeft);
1024 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1025 gui_layout->setRowStretch(row++, 1);
1027 gui_layout->addWidget(fallback_label, row, 0, Qt::AlignRight);
1028 gui_layout->addWidget(fallback_box, row++, 1, Qt::AlignLeft);
1030 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1031 gui_layout->setRowStretch(row++, 1);
1033 gui_layout->addWidget(limit_label, row, 0, Qt::AlignRight);
1034 gui_layout->addWidget(limit_box, row++, 1, Qt::AlignLeft);
1035 gui_layout->addWidget(no_limit_box, row++, 1);
1037 gui_layout->addWidget(increase_label, row, 0, Qt::AlignRight);
1038 gui_layout->addWidget(increase_box, row++, 1, Qt::AlignLeft);
1039 gui_layout->addWidget(no_increase_box, row++, 1);
1041 gui_layout->addWidget(snapping_label, row, 0, Qt::AlignRight);
1042 gui_layout->addWidget(snapping_line, row++, 1, Qt::AlignLeft);
1044 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1045 gui_layout->setRowStretch(row++, 1);
1047 gui_layout->addWidget(wincomp_box, row++, 1);
1048 gui_layout->addWidget(pre_box, row++, 1);
1049 gui_layout->addWidget(hint_box, row++, 1);
1050 gui_layout->addWidget(symbol_box, row++, 1);
1051 gui_layout->addWidget(info_box, row++, 1);
1053 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1054 gui_layout->setRowStretch(row++, 1);
1056 gui_layout->addWidget(stem_label, row, 0, Qt::AlignRight);
1057 gui_layout->addWidget(gray_box, row++, 1);
1058 gui_layout->addWidget(gdi_box, row++, 1);
1059 gui_layout->addWidget(dw_box, row++, 1);
1061 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1062 gui_layout->setRowStretch(row++, 1);
1064 gui_layout->addWidget(run_button, row++, 1, Qt::AlignRight);
1066 // create dummy widget to register layout
1067 QWidget* main_widget = new QWidget;
1068 main_widget->setLayout(gui_layout);
1069 setCentralWidget(main_widget);
1070 setWindowTitle("TTFautohint");
1074 void
1075 Main_GUI::create_connections()
1077 connect(input_button, SIGNAL(clicked()), this,
1078 SLOT(browse_input()));
1079 connect(output_button, SIGNAL(clicked()), this,
1080 SLOT(browse_output()));
1082 connect(input_line, SIGNAL(textChanged(QString)), this,
1083 SLOT(check_run()));
1084 connect(output_line, SIGNAL(textChanged(QString)), this,
1085 SLOT(check_run()));
1087 connect(input_line, SIGNAL(editingFinished()), this,
1088 SLOT(absolute_input()));
1089 connect(output_line, SIGNAL(editingFinished()), this,
1090 SLOT(absolute_output()));
1092 connect(min_box, SIGNAL(valueChanged(int)), this,
1093 SLOT(check_min()));
1094 connect(max_box, SIGNAL(valueChanged(int)), this,
1095 SLOT(check_max()));
1097 connect(limit_box, SIGNAL(valueChanged(int)), this,
1098 SLOT(check_limit()));
1099 connect(no_limit_box, SIGNAL(clicked()), this,
1100 SLOT(check_no_limit()));
1102 connect(no_increase_box, SIGNAL(clicked()), this,
1103 SLOT(check_no_increase()));
1105 connect(snapping_line, SIGNAL(editingFinished()), this,
1106 SLOT(check_number_set()));
1107 connect(snapping_line, SIGNAL(textEdited(QString)), this,
1108 SLOT(clear_status_bar()));
1110 connect(run_button, SIGNAL(clicked()), this,
1111 SLOT(run()));
1115 void
1116 Main_GUI::create_actions()
1118 exit_act = new QAction(tr("E&xit"), this);
1119 exit_act->setShortcuts(QKeySequence::Quit);
1120 connect(exit_act, SIGNAL(triggered()), this, SLOT(close()));
1122 about_act = new QAction(tr("&About"), this);
1123 connect(about_act, SIGNAL(triggered()), this, SLOT(about()));
1125 about_Qt_act = new QAction(tr("About &Qt"), this);
1126 connect(about_Qt_act, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
1130 void
1131 Main_GUI::create_menus()
1133 file_menu = menuBar()->addMenu(tr("&File"));
1134 file_menu->addAction(exit_act);
1136 help_menu = menuBar()->addMenu(tr("&Help"));
1137 help_menu->addAction(about_act);
1138 help_menu->addAction(about_Qt_act);
1142 void
1143 Main_GUI::create_status_bar()
1145 statusBar()->showMessage("");
1149 void
1150 Main_GUI::set_defaults()
1152 min_box->setValue(hinting_range_min);
1153 max_box->setValue(hinting_range_max);
1155 fallback_box->setCurrentIndex(latin_fallback);
1157 limit_box->setValue(hinting_limit ? hinting_limit : hinting_range_max);
1158 // handle command line option `--hinting-limit=0'
1159 if (!hinting_limit)
1161 hinting_limit = max_box->value();
1162 no_limit_box->setChecked(true);
1165 increase_box->setValue(increase_x_height ? increase_x_height
1166 : TA_INCREASE_X_HEIGHT);
1167 // handle command line option `--increase-x-height=0'
1168 if (!increase_x_height)
1170 increase_x_height = TA_INCREASE_X_HEIGHT;
1171 no_increase_box->setChecked(true);
1174 snapping_line->setText(x_height_snapping_exceptions_string);
1176 if (windows_compatibility)
1177 wincomp_box->setChecked(true);
1178 if (pre_hinting)
1179 pre_box->setChecked(true);
1180 if (hint_with_components)
1181 hint_box->setChecked(true);
1182 if (symbol)
1183 symbol_box->setChecked(true);
1184 if (!no_info)
1185 info_box->setChecked(true);
1187 if (gray_strong_stem_width)
1188 gray_box->setChecked(true);
1189 if (gdi_cleartype_strong_stem_width)
1190 gdi_box->setChecked(true);
1191 if (dw_cleartype_strong_stem_width)
1192 dw_box->setChecked(true);
1194 run_button->setEnabled(false);
1196 check_min();
1197 check_max();
1198 check_limit();
1200 check_no_limit();
1201 check_no_increase();
1202 check_number_set();
1206 void
1207 Main_GUI::read_settings()
1209 QSettings settings;
1210 // QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
1211 // QSize size = settings.value("size", QSize(400, 400)).toSize();
1212 // resize(size);
1213 // move(pos);
1217 void
1218 Main_GUI::write_settings()
1220 QSettings settings;
1221 // settings.setValue("pos", pos());
1222 // settings.setValue("size", size());
1225 // end of maingui.cpp