Minor renamings and type fiddling.
[ttfautohint.git] / frontend / maingui.cpp
blob243c21847e2bd2ca8bd7af15aed9a82d8381c8bc
1 // maingui.cpp
3 // Copyright (C) 2012-2014 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 // Shorthand for `tr' using a local `TRDOMAIN'.
41 #define Tr(text) QCoreApplication::translate(TRDOMAIN, text)
44 // the available script tags and its descriptions are directly extracted
45 // from `ttfautohint-scripts.h'
46 typedef struct Script_Names_
48 const char* tag;
49 const char* description;
50 } Script_Names;
52 #undef SCRIPT
53 #define SCRIPT(s, S, d, h, sc1, sc2, sc3) \
54 {#s, d},
56 const Script_Names script_names[] =
58 #include <ttfautohint-scripts.h>
59 {NULL, NULL}
63 Main_GUI::Main_GUI(bool horizontal_layout,
64 int range_min,
65 int range_max,
66 int limit,
67 bool gray,
68 bool gdi,
69 bool dw,
70 int increase,
71 const char* exceptions,
72 int stem_width,
73 bool ignore,
74 bool wincomp,
75 bool adjust,
76 bool composites,
77 bool no,
78 const char* dflt,
79 const char* fallback,
80 bool symb,
81 bool dh)
82 : hinting_range_min(range_min),
83 hinting_range_max(range_max),
84 hinting_limit(limit),
85 gray_strong_stem_width(gray),
86 gdi_cleartype_strong_stem_width(gdi),
87 dw_cleartype_strong_stem_width(dw),
88 increase_x_height(increase),
89 x_height_snapping_exceptions_string(exceptions),
90 fallback_stem_width(stem_width),
91 ignore_restrictions(ignore),
92 windows_compatibility(wincomp),
93 adjust_subglyphs(adjust),
94 hint_composites(composites),
95 no_info(no),
96 symbol(symb),
97 dehint(dh)
99 int i;
101 // map default script tag to an index,
102 // replacing an invalid one with the default value
103 int latn_script_idx = 0;
104 for (i = 0; script_names[i].tag; i++)
106 if (!strcmp("latn", script_names[i].tag))
107 latn_script_idx = i;
108 if (!strcmp(dflt, script_names[i].tag))
109 break;
111 default_script_idx = script_names[i].tag ? i : latn_script_idx;
113 // map fallback script tag to an index,
114 // replacing an invalid one with the default value
115 int none_script_idx = 0;
116 for (i = 0; script_names[i].tag; i++)
118 if (!strcmp("none", script_names[i].tag))
119 none_script_idx = i;
120 if (!strcmp(fallback, script_names[i].tag))
121 break;
123 fallback_script_idx = script_names[i].tag ? i : none_script_idx;
125 x_height_snapping_exceptions = NULL;
127 // if file watching is active, we regularly poll the file status
128 timer = new QTimer(this);
129 timer->setInterval(1000);
130 fileinfo_input_file.setCaching(false);
132 create_layout(horizontal_layout);
133 create_connections();
134 create_actions();
135 create_menus();
136 create_status_bar();
138 set_defaults();
139 read_settings();
141 setUnifiedTitleAndToolBarOnMac(true);
143 // XXX register translations somewhere and loop over them
144 if (QLocale::system().name() == "en_US")
145 locale = new QLocale;
146 else
147 locale = new QLocale(QLocale::C);
151 Main_GUI::~Main_GUI()
153 number_set_free(x_height_snapping_exceptions);
157 // overloading
159 void
160 Main_GUI::closeEvent(QCloseEvent* event)
162 write_settings();
163 event->accept();
167 void
168 Main_GUI::about()
170 QMessageBox::about(this,
171 tr("About TTFautohint"),
172 tr("<p>This is <b>TTFautohint</b> version %1<br>"
173 " Copyright %2 2011-2014<br>"
174 " by Werner Lemberg <tt>&lt;wl@gnu.org&gt;</tt></p>"
176 "<p><b>TTFautohint</b> adds new auto-generated hints"
177 " to a TrueType font or TrueType collection.</p>"
179 "<p>License:"
180 " <a href='http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/FTL.TXT'>FreeType"
181 " License (FTL)</a> or"
182 " <a href='http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/GPLv2.TXT'>GNU"
183 " GPLv2</a></p>")
184 .arg(VERSION)
185 .arg(QChar(0xA9)));
189 void
190 Main_GUI::browse_input()
192 // XXX remember last directory
193 QString file = QFileDialog::getOpenFileName(
194 this,
195 tr("Open Input File"),
196 QDir::homePath(),
197 "");
198 if (!file.isEmpty())
199 input_line->setText(QDir::toNativeSeparators(file));
203 void
204 Main_GUI::browse_output()
206 // XXX remember last directory
207 QString file = QFileDialog::getSaveFileName(
208 this,
209 tr("Open Output File"),
210 QDir::homePath(),
211 "");
213 if (!file.isEmpty())
214 output_line->setText(QDir::toNativeSeparators(file));
218 void
219 Main_GUI::check_min()
221 int min = min_box->value();
222 int max = max_box->value();
223 int limit = limit_box->value();
224 if (min > max)
225 max_box->setValue(min);
226 if (min > limit)
227 limit_box->setValue(min);
231 void
232 Main_GUI::check_max()
234 int min = min_box->value();
235 int max = max_box->value();
236 int limit = limit_box->value();
237 if (max < min)
238 min_box->setValue(max);
239 if (max > limit)
240 limit_box->setValue(max);
244 void
245 Main_GUI::check_limit()
247 int min = min_box->value();
248 int max = max_box->value();
249 int limit = limit_box->value();
250 if (limit < max)
251 max_box->setValue(limit);
252 if (limit < min)
253 min_box->setValue(limit);
257 void
258 Main_GUI::check_dehint()
260 if (dehint_box->isChecked())
262 min_label->setEnabled(false);
263 min_box->setEnabled(false);
265 max_label->setEnabled(false);
266 max_box->setEnabled(false);
268 default_label->setEnabled(false);
269 default_box->setEnabled(false);
270 fallback_label->setEnabled(false);
271 fallback_box->setEnabled(false);
273 no_limit_box->setEnabled(false);
274 limit_label->setEnabled(false);
275 limit_box->setEnabled(false);
277 no_increase_box->setEnabled(false);
278 increase_label->setEnabled(false);
279 increase_box->setEnabled(false);
281 snapping_label->setEnabled(false);
282 snapping_line->setEnabled(false);
284 default_stem_width_box->setEnabled(false);
285 stem_width_label->setEnabled(false);
286 stem_width_box->setEnabled(false);
288 wincomp_box->setEnabled(false);
289 adjust_box->setEnabled(false);
290 hint_box->setEnabled(false);
291 symbol_box->setEnabled(false);
293 stem_label->setEnabled(false);
294 gray_box->setEnabled(false);
295 gdi_box->setEnabled(false);
296 dw_box->setEnabled(false);
298 else
300 min_label->setEnabled(true);
301 min_box->setEnabled(true);
303 max_label->setEnabled(true);
304 max_box->setEnabled(true);
306 default_label->setEnabled(true);
307 default_box->setEnabled(true);
308 fallback_label->setEnabled(true);
309 fallback_box->setEnabled(true);
311 no_limit_box->setEnabled(true);
312 check_no_limit();
314 no_increase_box->setEnabled(true);
315 check_no_increase();
317 snapping_label->setEnabled(true);
318 snapping_line->setEnabled(true);
320 default_stem_width_box->setEnabled(true);
321 check_default_stem_width();
323 wincomp_box->setEnabled(true);
324 adjust_box->setEnabled(true);
325 hint_box->setEnabled(true);
326 symbol_box->setEnabled(true);
328 stem_label->setEnabled(true);
329 gray_box->setEnabled(true);
330 gdi_box->setEnabled(true);
331 dw_box->setEnabled(true);
336 void
337 Main_GUI::check_no_limit()
339 if (no_limit_box->isChecked())
341 limit_label->setEnabled(false);
342 limit_label->setText(limit_label_text);
343 limit_box->setEnabled(false);
344 no_limit_box->setText(no_limit_box_text_with_key);
346 else
348 limit_label->setEnabled(true);
349 limit_label->setText(limit_label_text_with_key);
350 limit_box->setEnabled(true);
351 no_limit_box->setText(no_limit_box_text);
356 void
357 Main_GUI::check_no_increase()
359 if (no_increase_box->isChecked())
361 increase_label->setEnabled(false);
362 increase_label->setText(increase_label_text);
363 increase_box->setEnabled(false);
364 no_increase_box->setText(no_increase_box_text_with_key);
366 else
368 increase_label->setEnabled(true);
369 increase_label->setText(increase_label_text_with_key);
370 increase_box->setEnabled(true);
371 no_increase_box->setText(no_increase_box_text);
376 void
377 Main_GUI::check_default_stem_width()
379 if (default_stem_width_box->isChecked())
381 stem_width_label->setEnabled(false);
382 stem_width_label->setText(stem_width_label_text);
383 stem_width_box->setEnabled(false);
384 default_stem_width_box->setText(default_stem_width_box_text_with_key);
386 else
388 stem_width_label->setEnabled(true);
389 stem_width_label->setText(stem_width_label_text_with_key);
390 stem_width_box->setEnabled(true);
391 default_stem_width_box->setText(default_stem_width_box_text);
396 void
397 Main_GUI::check_run()
399 if (input_line->text().isEmpty() || output_line->text().isEmpty())
400 run_button->setEnabled(false);
401 else
402 run_button->setEnabled(true);
406 void
407 Main_GUI::absolute_input()
409 QString input_name = QDir::fromNativeSeparators(input_line->text());
410 if (!input_name.isEmpty()
411 && QDir::isRelativePath(input_name))
413 QDir cur_path(QDir::currentPath() + "/" + input_name);
414 input_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
419 void
420 Main_GUI::absolute_output()
422 QString output_name = QDir::fromNativeSeparators(output_line->text());
423 if (!output_name.isEmpty()
424 && QDir::isRelativePath(output_name))
426 QDir cur_path(QDir::currentPath() + "/" + output_name);
427 output_line->setText(QDir::toNativeSeparators(cur_path.absolutePath()));
432 void
433 Main_GUI::check_number_set()
435 QString text = snapping_line->text();
436 QString qs;
438 // construct ASCII string from arbitrary Unicode data;
439 // the idea is to accept, say, CJK fullwidth digits also
440 for (int i = 0; i < text.size(); i++)
442 QChar c = text.at(i);
444 int digit = c.digitValue();
445 if (digit >= 0)
446 qs += QString::number(digit);
447 else if (c.isSpace())
448 qs += ' ';
449 // U+30FC KATAGANA-HIRAGANA PROLONGED SOUND MARK is assigned
450 // to the `-' key in some Japanese input methods
451 else if (c.category() == QChar::Punctuation_Dash
452 || c == QChar(0x30FC))
453 qs += '-';
454 // various Unicode COMMA characters,
455 // including representation forms
456 else if (c == QChar(',')
457 || c == QChar(0x055D)
458 || c == QChar(0x060C)
459 || c == QChar(0x07F8)
460 || c == QChar(0x1363)
461 || c == QChar(0x1802)
462 || c == QChar(0x1808)
463 || c == QChar(0x3001)
464 || c == QChar(0xA4FE)
465 || c == QChar(0xA60D)
466 || c == QChar(0xA6F5)
467 || c == QChar(0xFE10)
468 || c == QChar(0xFE11)
469 || c == QChar(0xFE50)
470 || c == QChar(0xFE51)
471 || c == QChar(0xFF0C)
472 || c == QChar(0xFF64))
473 qs += ',';
474 else
475 qs += c; // we do error handling below
478 if (x_height_snapping_exceptions)
479 number_set_free(x_height_snapping_exceptions);
481 QByteArray str = qs.toLocal8Bit();
482 const char* s = number_set_parse(str.constData(),
483 &x_height_snapping_exceptions,
484 6, 0x7FFF);
485 if (s && *s)
487 statusBar()->setStyleSheet("color: red;");
488 if (x_height_snapping_exceptions == NUMBERSET_ALLOCATION_ERROR)
489 statusBar()->showMessage(
490 tr("allocation error"));
491 else if (x_height_snapping_exceptions == NUMBERSET_INVALID_CHARACTER)
492 statusBar()->showMessage(
493 tr("invalid character (use digits, dashes, commas, and spaces)"));
494 else if (x_height_snapping_exceptions == NUMBERSET_OVERFLOW)
495 statusBar()->showMessage(
496 tr("overflow"));
497 else if (x_height_snapping_exceptions == NUMBERSET_INVALID_RANGE)
498 statusBar()->showMessage(
499 tr("invalid range (minimum is 6, maximum is 32767)"));
500 else if (x_height_snapping_exceptions == NUMBERSET_OVERLAPPING_RANGES)
501 statusBar()->showMessage(
502 tr("overlapping ranges"));
503 else if (x_height_snapping_exceptions == NUMBERSET_NOT_ASCENDING)
504 statusBar()->showMessage(
505 tr("values und ranges must be specified in ascending order"));
507 snapping_line->setText(qs);
508 snapping_line->setFocus(Qt::OtherFocusReason);
509 snapping_line->setCursorPosition(s - str.constData());
511 x_height_snapping_exceptions = NULL;
513 else
515 // normalize if there is no error
516 char* new_str = number_set_show(x_height_snapping_exceptions,
517 6, 0x7FFF);
518 snapping_line->setText(new_str);
519 free(new_str);
524 void
525 Main_GUI::clear_status_bar()
527 statusBar()->clearMessage();
528 statusBar()->setStyleSheet("");
533 Main_GUI::check_filenames(const QString& input_name,
534 const QString& output_name)
536 if (!QFile::exists(input_name))
538 QMessageBox::warning(
539 this,
540 "TTFautohint",
541 tr("The file %1 cannot be found.")
542 .arg(QUOTE_STRING(QDir::toNativeSeparators(input_name))),
543 QMessageBox::Ok,
544 QMessageBox::Ok);
545 return 0;
548 if (input_name == output_name)
550 QMessageBox::warning(
551 this,
552 "TTFautohint",
553 tr("Input and output file names must be different."),
554 QMessageBox::Ok,
555 QMessageBox::Ok);
556 return 0;
559 // silently overwrite if watching is active
560 if (QFile::exists(output_name) && !timer->isActive())
562 int ret = QMessageBox::warning(
563 this,
564 "TTFautohint",
565 tr("The file %1 already exists.\n"
566 "Overwrite?")
567 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name))),
568 QMessageBox::Yes | QMessageBox::No,
569 QMessageBox::No);
570 if (ret == QMessageBox::No)
571 return 0;
574 return 1;
579 Main_GUI::open_files(const QString& input_name,
580 FILE** in,
581 const QString& output_name,
582 FILE** out)
584 const int buf_len = 1024;
585 char buf[buf_len];
587 *in = fopen(qPrintable(input_name), "rb");
588 if (!*in)
590 strerror_r(errno, buf, buf_len);
591 QMessageBox::warning(
592 this,
593 "TTFautohint",
594 tr("The following error occurred while opening input file %1:\n")
595 .arg(QUOTE_STRING(QDir::toNativeSeparators(input_name)))
596 + QString::fromLocal8Bit(buf),
597 QMessageBox::Ok,
598 QMessageBox::Ok);
599 return 0;
602 *out = fopen(qPrintable(output_name), "wb");
603 if (!*out)
605 strerror_r(errno, buf, buf_len);
606 QMessageBox::warning(
607 this,
608 "TTFautohint",
609 tr("The following error occurred while opening output file %1:\n")
610 .arg(QUOTE_STRING(QDir::toNativeSeparators(output_name)))
611 + QString::fromLocal8Bit(buf),
612 QMessageBox::Ok,
613 QMessageBox::Ok);
614 return 0;
617 return 1;
621 void
622 Main_GUI::check_watch()
624 if (!watch_box->isChecked())
625 timer->stop();
626 // the timer gets started in the `run' function
630 void
631 Main_GUI::watch_files()
633 if (fileinfo_input_file.exists()
634 && fileinfo_input_file.isReadable())
636 QDateTime modified = fileinfo_input_file.lastModified();
637 if (modified > datetime_input_file)
638 run(); // this function sets `datetime_input_file'
640 else
641 run(); // let this routine handle all errors
645 extern "C" {
647 struct GUI_Progress_Data
649 long last_sfnt;
650 bool begin;
651 QProgressDialog* dialog;
655 #undef TRDOMAIN
656 #define TRDOMAIN "GuiProgress"
659 gui_progress(long curr_idx,
660 long num_glyphs,
661 long curr_sfnt,
662 long num_sfnts,
663 void* user)
665 GUI_Progress_Data* data = static_cast<GUI_Progress_Data*>(user);
667 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
669 data->dialog->setLabelText(Tr("Auto-hinting subfont %1 of %2"
670 " with %3 glyphs...")
671 .arg(curr_sfnt + 1)
672 .arg(num_sfnts)
673 .arg(num_glyphs));
675 if (curr_sfnt + 1 == num_sfnts)
677 data->dialog->setAutoReset(true);
678 data->dialog->setAutoClose(true);
680 else
682 data->dialog->setAutoReset(false);
683 data->dialog->setAutoClose(false);
686 data->last_sfnt = curr_sfnt;
687 data->begin = true;
690 if (data->begin)
692 if (num_sfnts == 1)
693 data->dialog->setLabelText(Tr("Auto-hinting %1 glyphs...")
694 .arg(num_glyphs));
695 data->dialog->setMaximum(num_glyphs - 1);
697 data->begin = false;
700 data->dialog->setValue(curr_idx);
702 if (data->dialog->wasCanceled())
703 return 1;
705 return 0;
709 struct GUI_Error_Data
711 Main_GUI* gui;
712 QLocale* locale;
713 QString output_name;
714 int* ignore_restrictions_p;
715 bool retry;
719 #undef TRDOMAIN
720 #define TRDOMAIN "GuiError"
722 void
723 gui_error(TA_Error error,
724 const char* error_string,
725 unsigned int /* errlinenum */,
726 const char* /* errline */,
727 const char* /* errpos */,
728 void* user)
730 GUI_Error_Data* data = static_cast<GUI_Error_Data*>(user);
731 QLocale* locale = data->locale; // for QUOTE_STRING_LITERAL
733 if (!error)
734 return;
736 if (error == TA_Err_Canceled)
738 else if (error == TA_Err_Invalid_FreeType_Version)
739 QMessageBox::critical(
740 data->gui,
741 "TTFautohint",
742 Tr("FreeType version 2.4.5 or higher is needed.\n"
743 "Are you perhaps using a wrong FreeType DLL?"),
744 QMessageBox::Ok,
745 QMessageBox::Ok);
746 else if (error == TA_Err_Invalid_Font_Type)
747 QMessageBox::warning(
748 data->gui,
749 "TTFautohint",
750 Tr("This font is not a valid font"
751 " in SFNT format with TrueType outlines.\n"
752 "In particular, CFF outlines are not supported."),
753 QMessageBox::Ok,
754 QMessageBox::Ok);
755 else if (error == TA_Err_Already_Processed)
756 QMessageBox::warning(
757 data->gui,
758 "TTFautohint",
759 Tr("This font has already been processed by TTFautohint."),
760 QMessageBox::Ok,
761 QMessageBox::Ok);
762 else if (error == TA_Err_Missing_Legal_Permission)
764 int yesno = QMessageBox::warning(
765 data->gui,
766 "TTFautohint",
767 Tr("Bit 1 in the %1 field of the %2 table is set:"
768 " This font must not be modified"
769 " without permission of the legal owner.\n"
770 "Do you have such a permission?")
771 .arg(QUOTE_STRING_LITERAL("fsType"))
772 .arg(QUOTE_STRING_LITERAL("OS/2")),
773 QMessageBox::Yes | QMessageBox::No,
774 QMessageBox::No);
775 if (yesno == QMessageBox::Yes)
777 *data->ignore_restrictions_p = true;
778 data->retry = true;
781 else if (error == TA_Err_Missing_Unicode_CMap)
782 QMessageBox::warning(
783 data->gui,
784 "TTFautohint",
785 Tr("The input font doesn't contain a Unicode character map.\n"
786 "Maybe you haven't set the %1 checkbox?")
787 .arg(QUOTE_STRING_LITERAL(Tr("Symbol Font"))),
788 QMessageBox::Ok,
789 QMessageBox::Ok);
790 else if (error == TA_Err_Missing_Symbol_CMap)
791 QMessageBox::warning(
792 data->gui,
793 "TTFautohint",
794 Tr("The input font does neither contain a symbol"
795 " nor a character map."),
796 QMessageBox::Ok,
797 QMessageBox::Ok);
798 else if (error == TA_Err_Missing_Glyph)
799 QMessageBox::warning(
800 data->gui,
801 "TTFautohint",
802 Tr("No glyph for a standard character"
803 " to derive standard width and height.\n"
804 "Please check the documentation for a list of"
805 " script-specific standard characters.\n"
806 "\n"
807 "Set the %1 checkbox if you want to circumvent this test.")
808 .arg(QUOTE_STRING_LITERAL(Tr("Symbol Font"))),
809 QMessageBox::Ok,
810 QMessageBox::Ok);
811 else
812 QMessageBox::warning(
813 data->gui,
814 "TTFautohint",
815 Tr("Error code 0x%1 while autohinting font:\n")
816 .arg(error, 2, 16, QLatin1Char('0'))
817 + QString::fromLocal8Bit((const char*)error_string),
818 QMessageBox::Ok,
819 QMessageBox::Ok);
821 if (QFile::exists(data->output_name)
822 && remove(qPrintable(data->output_name)))
824 const int buf_len = 1024;
825 char buf[buf_len];
827 strerror_r(errno, buf, buf_len);
828 QMessageBox::warning(
829 data->gui,
830 "TTFautohint",
831 Tr("The following error occurred while removing output file %1:\n")
832 .arg(QUOTE_STRING(QDir::toNativeSeparators(data->output_name)))
833 + QString::fromLocal8Bit(buf),
834 QMessageBox::Ok,
835 QMessageBox::Ok);
839 } // extern "C"
842 void
843 Main_GUI::run()
845 statusBar()->clearMessage();
847 QString input_name = QDir::fromNativeSeparators(input_line->text());
848 QString output_name = QDir::fromNativeSeparators(output_line->text());
849 if (!check_filenames(input_name, output_name))
851 timer->stop();
852 return;
855 // we need C file descriptors for communication with TTF_autohint
856 FILE* input;
857 FILE* output;
859 again:
860 if (!open_files(input_name, &input, output_name, &output))
862 timer->stop();
863 return;
866 QProgressDialog dialog;
867 dialog.setCancelButtonText(tr("Cancel"));
868 dialog.setMinimumDuration(1000);
869 dialog.setWindowModality(Qt::WindowModal);
871 TA_Info_Func info_func = info;
872 GUI_Progress_Data gui_progress_data = {-1, true, &dialog};
873 GUI_Error_Data gui_error_data = { this, locale, output_name,
874 &ignore_restrictions, false };
875 Info_Data info_data;
877 info_data.data = NULL; // must be deallocated after use
878 info_data.data_wide = NULL; // must be deallocated after use
879 info_data.data_len = 0;
880 info_data.data_wide_len = 0;
882 info_data.hinting_range_min = min_box->value();
883 info_data.hinting_range_max = max_box->value();
884 info_data.hinting_limit = no_limit_box->isChecked()
886 : limit_box->value();
888 info_data.gray_strong_stem_width = gray_box->isChecked();
889 info_data.gdi_cleartype_strong_stem_width = gdi_box->isChecked();
890 info_data.dw_cleartype_strong_stem_width = dw_box->isChecked();
892 info_data.increase_x_height = no_increase_box->isChecked()
894 : increase_box->value();
895 info_data.x_height_snapping_exceptions_string =
896 qPrintable(x_height_snapping_exceptions_string);
897 info_data.fallback_stem_width = default_stem_width_box->isChecked()
899 : stem_width_box->value();
901 info_data.windows_compatibility = wincomp_box->isChecked();
902 info_data.adjust_subglyphs = adjust_box->isChecked();
903 info_data.hint_composites = hint_box->isChecked();
904 info_data.symbol = symbol_box->isChecked();
905 info_data.dehint = dehint_box->isChecked();
907 strncpy(info_data.default_script,
908 script_names[default_box->currentIndex()].tag,
909 sizeof (info_data.default_script));
910 strncpy(info_data.fallback_script,
911 script_names[fallback_box->currentIndex()].tag,
912 sizeof (info_data.fallback_script));
914 if (info_box->isChecked())
916 int ret = build_version_string(&info_data);
917 if (ret == 1)
918 QMessageBox::information(
919 this,
920 "TTFautohint",
921 tr("Can't allocate memory for <b>TTFautohint</b> options string"
922 " in <i>name</i> table."),
923 QMessageBox::Ok,
924 QMessageBox::Ok);
925 else if (ret == 2)
926 QMessageBox::information(
927 this,
928 "TTFautohint",
929 tr("<b>TTFautohint</b> options string"
930 " in <i>name</i> table too long."),
931 QMessageBox::Ok,
932 QMessageBox::Ok);
934 else
935 info_func = NULL;
937 if (info_data.symbol
938 && info_data.fallback_stem_width
939 && !strcmp(info_data.fallback_script, "none"))
940 QMessageBox::information(
941 this,
942 "TTFautohint",
943 tr("Setting a fallback stem width for a symbol font"
944 " without setting a fallback script has no effect."),
945 QMessageBox::Ok,
946 QMessageBox::Ok);
948 fileinfo_input_file.setFile(input_name);
949 datetime_input_file = fileinfo_input_file.lastModified();
951 QByteArray snapping_string = snapping_line->text().toLocal8Bit();
953 TA_Error error =
954 TTF_autohint("in-file, out-file,"
955 "hinting-range-min, hinting-range-max,"
956 "hinting-limit,"
957 "gray-strong-stem-width,"
958 "gdi-cleartype-strong-stem-width,"
959 "dw-cleartype-strong-stem-width,"
960 "progress-callback, progress-callback-data,"
961 "error-callback, error-callback-data,"
962 "info-callback, info-callback-data,"
963 "ignore-restrictions,"
964 "windows-compatibility,"
965 "adjust-subglyphs,"
966 "hint-composites,"
967 "increase-x-height,"
968 "x-height-snapping-exceptions, fallback-stem-width,"
969 "default-script, fallback-script,"
970 "symbol, dehint",
971 input, output,
972 info_data.hinting_range_min, info_data.hinting_range_max,
973 info_data.hinting_limit,
974 info_data.gray_strong_stem_width,
975 info_data.gdi_cleartype_strong_stem_width,
976 info_data.dw_cleartype_strong_stem_width,
977 gui_progress, &gui_progress_data,
978 gui_error, &gui_error_data,
979 info_func, &info_data,
980 ignore_restrictions,
981 info_data.windows_compatibility,
982 info_data.adjust_subglyphs,
983 info_data.hint_composites,
984 info_data.increase_x_height,
985 snapping_string.constData(), info_data.fallback_stem_width,
986 info_data.default_script, info_data.fallback_script,
987 info_data.symbol, info_data.dehint);
989 if (info_box->isChecked())
991 free(info_data.data);
992 free(info_data.data_wide);
995 fclose(input);
996 fclose(output);
998 if (error)
1000 // retry if there is a user request to do so (handled in `gui_error')
1001 if (gui_error_data.retry)
1002 goto again;
1004 timer->stop();
1006 else
1008 statusBar()->showMessage(tr("Auto-hinting finished")
1009 + " ("
1010 + QDateTime::currentDateTime()
1011 .toString(Qt::TextDate)
1012 + ").");
1014 // we have successfully processed a file;
1015 // start file watching now if requested
1016 if (watch_box->isChecked())
1017 timer->start();
1022 // XXX distances are specified in pixels,
1023 // making the layout dependent on the output device resolution
1024 void
1025 Main_GUI::create_layout(bool horizontal_layout)
1028 // file stuff
1030 QCompleter* completer = new QCompleter(this);
1031 QFileSystemModel* model = new QFileSystemModel(completer);
1032 model->setRootPath(QDir::rootPath());
1033 completer->setModel(model);
1035 input_label = new QLabel(tr("&Input File:"));
1036 input_line = new Drag_Drop_Line_Edit(DRAG_DROP_TRUETYPE);
1037 input_button = new QPushButton(tr("Browse..."));
1038 input_label->setBuddy(input_line);
1039 // enforce rich text to get nice word wrapping
1040 input_label->setToolTip(
1041 tr("<b></b>The input file, either a TrueType font (TTF),"
1042 " TrueType collection (TTC), or a TrueType-based OpenType font."));
1043 input_line->setCompleter(completer);
1045 output_label = new QLabel(tr("&Output File:"));
1046 output_line = new Drag_Drop_Line_Edit(DRAG_DROP_TRUETYPE);
1047 output_button = new QPushButton(tr("Browse..."));
1048 output_label->setBuddy(output_line);
1049 output_label->setToolTip(
1050 tr("<b></b>The output file, which will be essentially identical"
1051 " to the input font but will contain new, generated hints."));
1052 output_line->setCompleter(completer);
1055 // minmax controls
1057 min_label = new QLabel(tr("Hint Set Range Mi&nimum:"));
1058 min_box = new QSpinBox;
1059 min_label->setBuddy(min_box);
1060 min_label->setToolTip(
1061 tr("The minimum PPEM value of the range for which"
1062 " <b>TTFautohint</b> computes <i>hint sets</i>."
1063 " A hint set for a given PPEM value hints this size optimally."
1064 " The larger the range, the more hint sets are considered,"
1065 " usually increasing the size of the bytecode.<br>"
1066 "Note that changing this range doesn't influence"
1067 " the <i>gasp</i> table:"
1068 " Hinting is enabled for all sizes."));
1069 min_box->setKeyboardTracking(false);
1070 min_box->setRange(2, 10000);
1072 max_label = new QLabel(tr("Hint Set Range Ma&ximum:"));
1073 max_box = new QSpinBox;
1074 max_label->setBuddy(max_box);
1075 max_label->setToolTip(
1076 tr("The maximum PPEM value of the range for which"
1077 " <b>TTFautohint</b> computes <i>hint sets</i>."
1078 " A hint set for a given PPEM value hints this size optimally."
1079 " The larger the range, the more hint sets are considered,"
1080 " usually increasing the size of the bytecode.<br>"
1081 "Note that changing this range doesn't influence"
1082 " the <i>gasp</i> table:"
1083 " Hinting is enabled for all sizes."));
1084 max_box->setKeyboardTracking(false);
1085 max_box->setRange(2, 10000);
1088 // OpenType default script
1090 default_label = new QLabel(tr("Defa&ult Script:"));
1091 default_box = new QComboBox;
1092 default_label->setBuddy(default_box);
1093 default_label->setToolTip(
1094 tr("This sets the default script for OpenType features:"
1095 " After applying all features that are handled specially"
1096 " (for example small caps or superscript glyphs),"
1097 " <b>TTFautohint</b> uses this value for the remaining features."));
1098 for (int i = 0; script_names[i].tag; i++)
1100 // XXX: how to provide translations?
1101 default_box->insertItem(i,
1102 QString("%1 (%2)")
1103 .arg(script_names[i].tag)
1104 .arg(script_names[i].description));
1108 // hinting and fallback controls
1110 fallback_label = new QLabel(tr("Fallback &Script:"));
1111 fallback_box = new QComboBox;
1112 fallback_label->setBuddy(fallback_box);
1113 fallback_label->setToolTip(
1114 tr("This sets the fallback script for glyphs"
1115 " that <b>TTFautohint</b> can't map to a script automatically."));
1116 for (int i = 0; script_names[i].tag; i++)
1118 // XXX: how to provide translations?
1119 fallback_box->insertItem(i,
1120 QString("%1 (%2)")
1121 .arg(script_names[i].tag)
1122 .arg(script_names[i].description));
1126 // hinting limit
1128 limit_label_text_with_key = tr("Hinting &Limit:");
1129 limit_label_text = tr("Hinting Limit:");
1130 limit_label = new QLabel(limit_label_text_with_key);
1131 limit_box = new QSpinBox;
1132 limit_label->setBuddy(limit_box);
1133 limit_label->setToolTip(
1134 tr("Switch off hinting for PPEM values exceeding this limit."
1135 " Changing this value does not influence the size of the bytecode.<br>"
1136 "Note that <b>TTFautohint</b> handles this feature"
1137 " in the output font's bytecode and not in the <i>gasp</i> table."));
1138 limit_box->setKeyboardTracking(false);
1139 limit_box->setRange(2, 10000);
1141 no_limit_box_text_with_key = tr("No Hinting &Limit");
1142 no_limit_box_text = tr("No Hinting Limit");
1143 no_limit_box = new QCheckBox(no_limit_box_text, this);
1144 no_limit_box->setToolTip(
1145 tr("If switched on, <b>TTFautohint</b> adds no hinting limit"
1146 " to the bytecode.<br>"
1147 "For testing only."));
1150 // x height increase limit
1152 increase_label_text_with_key = tr("x Height In&crease Limit:");
1153 increase_label_text = tr("x Height Increase Limit:");
1154 increase_label = new QLabel(increase_label_text_with_key);
1155 increase_box = new QSpinBox;
1156 increase_label->setBuddy(increase_box);
1157 increase_label->setToolTip(
1158 tr("For PPEM values in the range 5&nbsp;&lt; PPEM &lt;&nbsp;<i>n</i>,"
1159 " where <i>n</i> is the value selected by this spin box,"
1160 " round up the font's x&nbsp;height much more often than normally.<br>"
1161 "Use this if holes in letters like <i>e</i> get filled,"
1162 " for example."));
1163 increase_box->setKeyboardTracking(false);
1164 increase_box->setRange(6, 10000);
1166 no_increase_box_text_with_key = tr("No x Height In&crease");
1167 no_increase_box_text = tr("No x Height Increase");
1168 no_increase_box = new QCheckBox(no_increase_box_text, this);
1169 no_increase_box->setToolTip(
1170 tr("If switched on,"
1171 " <b>TTFautohint</b> does not increase the x&nbsp;height."));
1174 // x height snapping exceptions
1176 snapping_label = new QLabel(tr("x Height Snapping Excep&tions:"));
1177 snapping_line = new Tooltip_Line_Edit;
1178 snapping_label->setBuddy(snapping_line);
1179 snapping_label->setToolTip(
1180 tr("<p>A list of comma separated PPEM values or value ranges"
1181 " at which no x&nbsp;height snapping shall be applied"
1182 " (x&nbsp;height snapping usually slightly increases"
1183 " the size of all glyphs).</p>"
1185 "Examples:<br>"
1186 "&nbsp;&nbsp;<tt>2, 3-5, 12-17</tt><br>"
1187 "&nbsp;&nbsp;<tt>-20, 40-</tt>"
1188 " (meaning PPEM &le; 20 or PPEM &ge; 40)<br>"
1189 "&nbsp;&nbsp;<tt>-</tt> (meaning all possible PPEM values)"));
1192 // fallback stem width
1194 stem_width_label_text_with_key = tr("Fall&back Stem Width:");
1195 stem_width_label_text = tr("Fallback Stem Width:");
1196 stem_width_label = new QLabel(stem_width_label_text_with_key);
1197 stem_width_box = new QSpinBox;
1198 stem_width_label->setBuddy(stem_width_box);
1199 stem_width_label->setToolTip(
1200 tr("Set horizontal stem width (in font units) for all scripts"
1201 " that lack proper standard characters in the font.<br>"
1202 "If not set, <b>TTFautohint</b> uses a hard-coded default value."));
1203 stem_width_box->setKeyboardTracking(false);
1204 stem_width_box->setRange(1, 10000);
1206 default_stem_width_box_text_with_key = tr("Default Fall&back Stem Width");
1207 default_stem_width_box_text = tr("Default Fallback Stem Width");
1208 default_stem_width_box = new QCheckBox(default_stem_width_box_text, this);
1209 default_stem_width_box->setToolTip(
1210 tr("If switched on, <b>TTFautohint</b> uses a default value"
1211 " for the fallback stem width (50 font units at 2048 UPEM)."));
1214 // flags
1216 wincomp_box = new QCheckBox(tr("Windows Com&patibility"), this);
1217 wincomp_box->setToolTip(
1218 tr("If switched on, add two artificial blue zones positioned at the"
1219 " <tt>usWinAscent</tt> and <tt>usWinDescent</tt> values"
1220 " (from the font's <i>OS/2</i> table)."
1221 " This option, usually in combination"
1222 " with value <tt>-</tt> (a single dash)"
1223 " for the <i>x&nbsp;Height Snapping Exceptions</i> option,"
1224 " should be used if those two <i>OS/2</i> values are tight,"
1225 " and you are experiencing clipping during rendering."));
1227 adjust_box = new QCheckBox(tr("Ad&just Subglyphs"), this);
1228 adjust_box->setToolTip(
1229 tr("If switched on, the original bytecode of the input font"
1230 " gets applied (at EM size, usually 2048ppem)"
1231 " to derive the glyph outlines for <b>TTFautohint</b>.<br>"
1232 "Use this option only if subglyphs"
1233 " are incorrectly scaled and shifted.<br>"
1234 "Note that the original bytecode will always be discarded."));
1236 hint_box = new QCheckBox(tr("Hint Co&mposites")
1237 + " ", this); // make label wider
1238 hint_box->setToolTip(
1239 tr("If switched on, <b>TTFautohint</b> hints composite glyphs"
1240 " as a whole, including subglyphs."
1241 " Otherwise, glyph components get hinted separately.<br>"
1242 "Deactivating this flag reduces the bytecode size enormously,"
1243 " however, it might yield worse results."));
1245 symbol_box = new QCheckBox(tr("S&ymbol Font"), this);
1246 symbol_box->setToolTip(
1247 tr("If switched on, <b>TTFautohint</b> accepts fonts"
1248 " that don't contain a single standard character"
1249 " for any of the supported scripts.<br>"
1250 "Use this for symbol or dingbat fonts, for example."));
1252 dehint_box = new QCheckBox(tr("&Dehint"), this);
1253 dehint_box->setToolTip(
1254 tr("If set, remove all hints from the font.<br>"
1255 "For testing only."));
1257 info_box = new QCheckBox(tr("Add ttf&autohint Info"), this);
1258 info_box->setToolTip(
1259 tr("If switched on, information about <b>TTFautohint</b>"
1260 " and its calling parameters are added to the version string(s)"
1261 " (name ID&nbsp;5) in the <i>name</i> table."));
1264 // stem width and positioning
1266 stem_label = new QLabel(tr("Stron&g Stem Width and Positioning:"));
1267 stem_label->setToolTip(
1268 tr("<b>TTFautohint</b> provides two different hinting algorithms"
1269 " that can be selected for various hinting modes."
1271 "<p><i>strong</i> (checkbox set):"
1272 " Position horizontal stems and snap stem widths"
1273 " to integer pixel values. While making the output look crisper,"
1274 " outlines become more distorted.</p>"
1276 "<p><i>smooth</i> (checkbox not set):"
1277 " Use discrete values for horizontal stems and stem widths."
1278 " This only slightly increases the contrast"
1279 " but avoids larger outline distortion.</p>"));
1281 gray_box = new QCheckBox(tr("Grayscale"), this);
1282 gray_box->setToolTip(
1283 tr("<b></b>Grayscale rendering, no ClearType activated."));
1284 stem_label->setBuddy(gray_box);
1286 gdi_box = new QCheckBox(tr("GDI ClearType"), this);
1287 gdi_box->setToolTip(
1288 tr("GDI ClearType rendering,"
1289 " introduced in 2000 for Windows XP.<br>"
1290 "The rasterizer version (as returned by the"
1291 " GETINFO bytecode instruction) is in the range"
1292 " 36&nbsp;&le; version &lt;&nbsp;38, and ClearType is enabled.<br>"
1293 "Along the vertical axis, this mode behaves like B/W rendering."));
1295 dw_box = new QCheckBox(tr("DW ClearType"), this);
1296 dw_box->setToolTip(
1297 tr("DirectWrite ClearType rendering,"
1298 " introduced in 2008 for Windows Vista.<br>"
1299 "The rasterizer version (as returned by the"
1300 " GETINFO bytecode instruction) is &ge;&nbsp;38,"
1301 " ClearType is enabled, and subpixel positioning is enabled also.<br>"
1302 "Smooth rendering along the vertical axis."));
1305 // running
1307 watch_box = new QCheckBox(tr("&Watch Input File"), this);
1308 watch_box->setToolTip(
1309 tr("If switched on, <b>TTFautohint</b> automatically re-runs"
1310 " the hinting process as soon as the input file is modified.<br>"
1311 "Pressing the %1 button starts watching.<br>"
1312 "If an error occurs, watching stops and must be restarted"
1313 " with the %1 button.")
1314 .arg(QUOTE_STRING_LITERAL(tr("Run"))));
1316 run_button = new QPushButton(" "
1317 + tr("&Run")
1318 + " "); // make label wider
1320 if (horizontal_layout)
1321 create_horizontal_layout();
1322 else
1323 create_vertical_layout();
1327 // XXX distances are specified in pixels,
1328 // making the layout dependent on the output device resolution
1329 void
1330 Main_GUI::create_vertical_layout()
1332 // top area
1333 QGridLayout* file_layout = new QGridLayout;
1335 file_layout->addWidget(input_label, 0, 0, Qt::AlignRight);
1336 file_layout->addWidget(input_line, 0, 1);
1337 file_layout->addWidget(input_button, 0, 2);
1339 file_layout->setRowStretch(1, 1);
1341 file_layout->addWidget(output_label, 2, 0, Qt::AlignRight);
1342 file_layout->addWidget(output_line, 2, 1);
1343 file_layout->addWidget(output_button, 2, 2);
1345 // bottom area
1346 QGridLayout* run_layout = new QGridLayout;
1348 run_layout->addWidget(watch_box, 0, 1);
1349 run_layout->addWidget(run_button, 0, 3, Qt::AlignRight);
1350 run_layout->setColumnStretch(0, 1);
1351 run_layout->setColumnStretch(2, 2);
1354 // the whole gui
1356 QGridLayout* gui_layout = new QGridLayout;
1357 QFrame* hline = new QFrame;
1358 hline->setFrameShape(QFrame::HLine);
1359 int row = 0; // this counter simplifies inserting new items
1361 gui_layout->setRowMinimumHeight(row, 10); // XXX urgh, pixels...
1362 gui_layout->setRowStretch(row++, 1);
1364 gui_layout->addLayout(file_layout, row, 0, row, -1);
1365 gui_layout->setRowStretch(row++, 1);
1367 gui_layout->addWidget(hline, row, 0, row, -1);
1368 gui_layout->setRowStretch(row++, 1);
1370 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1371 gui_layout->setRowStretch(row++, 1);
1373 gui_layout->addWidget(min_label, row, 0, Qt::AlignRight);
1374 gui_layout->addWidget(min_box, row++, 1, Qt::AlignLeft);
1375 gui_layout->addWidget(max_label, row, 0, Qt::AlignRight);
1376 gui_layout->addWidget(max_box, row++, 1, Qt::AlignLeft);
1378 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1379 gui_layout->setRowStretch(row++, 1);
1381 gui_layout->addWidget(default_label, row, 0, Qt::AlignRight);
1382 gui_layout->addWidget(default_box, row++, 1, Qt::AlignLeft);
1383 gui_layout->addWidget(fallback_label, row, 0, Qt::AlignRight);
1384 gui_layout->addWidget(fallback_box, row++, 1, Qt::AlignLeft);
1386 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1387 gui_layout->setRowStretch(row++, 1);
1389 gui_layout->addWidget(limit_label, row, 0, Qt::AlignRight);
1390 gui_layout->addWidget(limit_box, row++, 1, Qt::AlignLeft);
1391 gui_layout->addWidget(no_limit_box, row++, 1);
1393 gui_layout->addWidget(increase_label, row, 0, Qt::AlignRight);
1394 gui_layout->addWidget(increase_box, row++, 1, Qt::AlignLeft);
1395 gui_layout->addWidget(no_increase_box, row++, 1);
1397 gui_layout->addWidget(snapping_label, row, 0, Qt::AlignRight);
1398 gui_layout->addWidget(snapping_line, row++, 1, Qt::AlignLeft);
1400 gui_layout->addWidget(stem_width_label, row, 0, Qt::AlignRight);
1401 gui_layout->addWidget(stem_width_box, row++, 1, Qt::AlignLeft);
1402 gui_layout->addWidget(default_stem_width_box, row++, 1);
1404 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1405 gui_layout->setRowStretch(row++, 1);
1407 gui_layout->addWidget(wincomp_box, row++, 1);
1408 gui_layout->addWidget(adjust_box, row++, 1);
1409 gui_layout->addWidget(hint_box, row++, 1);
1410 gui_layout->addWidget(symbol_box, row++, 1);
1411 gui_layout->addWidget(dehint_box, row++, 1);
1412 gui_layout->addWidget(info_box, row++, 1);
1414 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1415 gui_layout->setRowStretch(row++, 1);
1417 gui_layout->addWidget(stem_label, row, 0, Qt::AlignRight);
1418 gui_layout->addWidget(gray_box, row++, 1);
1419 gui_layout->addWidget(gdi_box, row++, 1);
1420 gui_layout->addWidget(dw_box, row++, 1);
1422 gui_layout->setRowMinimumHeight(row, 30); // XXX urgh, pixels...
1423 gui_layout->setRowStretch(row++, 1);
1425 gui_layout->addLayout(run_layout, row, 0, row, -1);
1427 // create dummy widget to register layout
1428 QWidget* main_widget = new QWidget;
1429 main_widget->setLayout(gui_layout);
1430 setCentralWidget(main_widget);
1431 setWindowTitle("TTFautohint");
1435 // XXX distances are specified in pixels,
1436 // making the layout dependent on the output device resolution
1437 void
1438 Main_GUI::create_horizontal_layout()
1440 // top area
1441 QGridLayout* file_layout = new QGridLayout;
1443 file_layout->addWidget(input_label, 0, 0, Qt::AlignRight);
1444 file_layout->addWidget(input_line, 0, 1);
1445 file_layout->addWidget(input_button, 0, 2);
1447 file_layout->setRowStretch(1, 1);
1449 file_layout->addWidget(output_label, 2, 0, Qt::AlignRight);
1450 file_layout->addWidget(output_line, 2, 1);
1451 file_layout->addWidget(output_button, 2, 2);
1453 // bottom area
1454 QGridLayout* run_layout = new QGridLayout;
1456 run_layout->addWidget(watch_box, 0, 1);
1457 run_layout->addWidget(run_button, 0, 3, Qt::AlignRight);
1458 run_layout->setColumnStretch(0, 2);
1459 run_layout->setColumnStretch(2, 3);
1460 run_layout->setColumnStretch(4, 1);
1463 // the whole gui
1465 QGridLayout* gui_layout = new QGridLayout;
1466 QFrame* hline = new QFrame;
1467 hline->setFrameShape(QFrame::HLine);
1468 int row = 0; // this counter simplifies inserting new items
1470 // margin
1471 gui_layout->setColumnMinimumWidth(0, 10); // XXX urgh, pixels...
1472 gui_layout->setColumnStretch(0, 1);
1474 // left
1475 gui_layout->setRowMinimumHeight(row, 10); // XXX urgh, pixels...
1476 gui_layout->setRowStretch(row++, 1);
1478 gui_layout->addLayout(file_layout, row, 0, row, -1);
1479 gui_layout->setRowStretch(row++, 1);
1481 gui_layout->addWidget(hline, row, 0, row, -1);
1482 gui_layout->setRowStretch(row++, 1);
1484 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1485 gui_layout->setRowStretch(row++, 1);
1487 gui_layout->addWidget(min_label, row, 1, Qt::AlignRight);
1488 gui_layout->addWidget(min_box, row++, 2, Qt::AlignLeft);
1489 gui_layout->addWidget(max_label, row, 1, Qt::AlignRight);
1490 gui_layout->addWidget(max_box, row++, 2, Qt::AlignLeft);
1492 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1493 gui_layout->setRowStretch(row++, 1);
1495 gui_layout->addWidget(default_label, row, 1, Qt::AlignRight);
1496 gui_layout->addWidget(default_box, row++, 2, Qt::AlignLeft);
1497 gui_layout->addWidget(fallback_label, row, 1, Qt::AlignRight);
1498 gui_layout->addWidget(fallback_box, row++, 2, Qt::AlignLeft);
1500 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1501 gui_layout->setRowStretch(row++, 1);
1503 gui_layout->addWidget(limit_label, row, 1, Qt::AlignRight);
1504 gui_layout->addWidget(limit_box, row++, 2, Qt::AlignLeft);
1505 gui_layout->addWidget(no_limit_box, row++, 2);
1507 gui_layout->addWidget(increase_label, row, 1, Qt::AlignRight);
1508 gui_layout->addWidget(increase_box, row++, 2, Qt::AlignLeft);
1509 gui_layout->addWidget(no_increase_box, row++, 2);
1511 gui_layout->addWidget(snapping_label, row, 1, Qt::AlignRight);
1512 gui_layout->addWidget(snapping_line, row++, 2, Qt::AlignLeft);
1514 gui_layout->addWidget(stem_width_label, row, 1, Qt::AlignRight);
1515 gui_layout->addWidget(stem_width_box, row++, 2, Qt::AlignLeft);
1516 gui_layout->addWidget(default_stem_width_box, row++, 2);
1518 gui_layout->setRowMinimumHeight(row, 30); // XXX urgh, pixels...
1519 gui_layout->setRowStretch(row++, 1);
1521 gui_layout->addLayout(run_layout, row, 0, row, -1);
1523 // column separator
1524 gui_layout->setColumnMinimumWidth(3, 20); // XXX urgh, pixels...
1525 gui_layout->setColumnStretch(3, 1);
1527 // right
1528 row = 4;
1529 gui_layout->addWidget(wincomp_box, row++, 4);
1530 gui_layout->addWidget(adjust_box, row++, 4);
1531 gui_layout->addWidget(hint_box, row++, 4);
1532 gui_layout->addWidget(symbol_box, row++, 4);
1533 gui_layout->addWidget(dehint_box, row++, 4);
1534 gui_layout->addWidget(info_box, row++, 4);
1536 gui_layout->setRowMinimumHeight(row, 20); // XXX urgh, pixels...
1537 gui_layout->setRowStretch(row++, 1);
1539 gui_layout->addWidget(stem_label, row++, 4);
1541 QGridLayout* stem_layout = new QGridLayout;
1542 stem_layout->setColumnMinimumWidth(0, 20); // XXX urgh, pixels...
1543 stem_layout->addWidget(gray_box, 0, 1);
1544 stem_layout->addWidget(gdi_box, 1, 1);
1545 stem_layout->addWidget(dw_box, 2, 1);
1547 gui_layout->addLayout(stem_layout, row, 4, 3, 1);
1548 row += 3;
1550 // margin
1551 gui_layout->setColumnMinimumWidth(5, 10); // XXX urgh, pixels...
1552 gui_layout->setColumnStretch(5, 1);
1554 // create dummy widget to register layout
1555 QWidget* main_widget = new QWidget;
1556 main_widget->setLayout(gui_layout);
1557 setCentralWidget(main_widget);
1558 setWindowTitle("TTFautohint");
1562 void
1563 Main_GUI::create_connections()
1565 connect(input_button, SIGNAL(clicked()), this,
1566 SLOT(browse_input()));
1567 connect(output_button, SIGNAL(clicked()), this,
1568 SLOT(browse_output()));
1570 connect(input_line, SIGNAL(textChanged(QString)), this,
1571 SLOT(check_run()));
1572 connect(output_line, SIGNAL(textChanged(QString)), this,
1573 SLOT(check_run()));
1575 connect(input_line, SIGNAL(editingFinished()), this,
1576 SLOT(absolute_input()));
1577 connect(output_line, SIGNAL(editingFinished()), this,
1578 SLOT(absolute_output()));
1580 connect(min_box, SIGNAL(valueChanged(int)), this,
1581 SLOT(check_min()));
1582 connect(max_box, SIGNAL(valueChanged(int)), this,
1583 SLOT(check_max()));
1585 connect(limit_box, SIGNAL(valueChanged(int)), this,
1586 SLOT(check_limit()));
1587 connect(no_limit_box, SIGNAL(clicked()), this,
1588 SLOT(check_no_limit()));
1590 connect(no_increase_box, SIGNAL(clicked()), this,
1591 SLOT(check_no_increase()));
1593 connect(snapping_line, SIGNAL(editingFinished()), this,
1594 SLOT(check_number_set()));
1595 connect(snapping_line, SIGNAL(textEdited(QString)), this,
1596 SLOT(clear_status_bar()));
1598 connect(default_stem_width_box, SIGNAL(clicked()), this,
1599 SLOT(check_default_stem_width()));
1601 connect(dehint_box, SIGNAL(clicked()), this,
1602 SLOT(check_dehint()));
1604 connect(timer, SIGNAL(timeout()), this,
1605 SLOT(watch_files()));
1607 connect(watch_box, SIGNAL(clicked()), this,
1608 SLOT(check_watch()));
1610 connect(run_button, SIGNAL(clicked()), this,
1611 SLOT(run()));
1615 void
1616 Main_GUI::create_actions()
1618 exit_act = new QAction(tr("E&xit"), this);
1619 exit_act->setShortcuts(QKeySequence::Quit);
1620 connect(exit_act, SIGNAL(triggered()), this, SLOT(close()));
1622 about_act = new QAction(tr("&About"), this);
1623 connect(about_act, SIGNAL(triggered()), this, SLOT(about()));
1625 about_Qt_act = new QAction(tr("About &Qt"), this);
1626 connect(about_Qt_act, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
1630 void
1631 Main_GUI::create_menus()
1633 file_menu = menuBar()->addMenu(tr("&File"));
1634 file_menu->addAction(exit_act);
1636 help_menu = menuBar()->addMenu(tr("&Help"));
1637 help_menu->addAction(about_act);
1638 help_menu->addAction(about_Qt_act);
1642 void
1643 Main_GUI::create_status_bar()
1645 statusBar()->showMessage("");
1649 void
1650 Main_GUI::set_defaults()
1652 min_box->setValue(hinting_range_min);
1653 max_box->setValue(hinting_range_max);
1655 default_box->setCurrentIndex(default_script_idx);
1656 fallback_box->setCurrentIndex(fallback_script_idx);
1658 limit_box->setValue(hinting_limit ? hinting_limit : hinting_range_max);
1659 // handle command line option `--hinting-limit=0'
1660 if (!hinting_limit)
1662 hinting_limit = max_box->value();
1663 no_limit_box->setChecked(true);
1666 increase_box->setValue(increase_x_height ? increase_x_height
1667 : TA_INCREASE_X_HEIGHT);
1668 // handle command line option `--increase-x-height=0'
1669 if (!increase_x_height)
1671 increase_x_height = TA_INCREASE_X_HEIGHT;
1672 no_increase_box->setChecked(true);
1675 snapping_line->setText(x_height_snapping_exceptions_string);
1677 if (fallback_stem_width)
1678 stem_width_box->setValue(fallback_stem_width);
1679 else
1681 stem_width_box->setValue(50);
1682 default_stem_width_box->setChecked(true);
1685 if (windows_compatibility)
1686 wincomp_box->setChecked(true);
1687 if (adjust_subglyphs)
1688 adjust_box->setChecked(true);
1689 if (hint_composites)
1690 hint_box->setChecked(true);
1691 if (symbol)
1692 symbol_box->setChecked(true);
1693 if (dehint)
1694 dehint_box->setChecked(true);
1695 if (!no_info)
1696 info_box->setChecked(true);
1698 if (gray_strong_stem_width)
1699 gray_box->setChecked(true);
1700 if (gdi_cleartype_strong_stem_width)
1701 gdi_box->setChecked(true);
1702 if (dw_cleartype_strong_stem_width)
1703 dw_box->setChecked(true);
1705 run_button->setEnabled(false);
1707 check_min();
1708 check_max();
1709 check_limit();
1711 check_no_limit();
1712 check_no_increase();
1713 check_number_set();
1715 // do this last since it disables almost everything
1716 check_dehint();
1720 void
1721 Main_GUI::read_settings()
1723 QSettings settings;
1724 // QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
1725 // QSize size = settings.value("size", QSize(400, 400)).toSize();
1726 // resize(size);
1727 // move(pos);
1731 void
1732 Main_GUI::write_settings()
1734 QSettings settings;
1735 // settings.setValue("pos", pos());
1736 // settings.setValue("size", size());
1739 // end of maingui.cpp