Commits:
-
5aaf34ba
by Charlie Jiang
at 2022-09-04T22:51:27+08:00
[ftinspect] Support MM/GX.
* src/ftinspect/panels/settingpanelmmgx.cpp,
src/ftinspect/panels/settingpanelmmgx.hpp:
Add GUI widgets for MM/GX settings.
* src/ftinspect/engine/mmgx.cpp, src/ftinspect/engine/mmgx.hpp:
Add `MMGXAxisInfo` to retrieve axes info. However, the SFNT name table
isn't implemented, so the SFNT based axis names are unavailable.
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Add `applyMMGXDesignCoords`. Add getters `currentFontMMGXState` and
`currentFontMMGXAxes`. Info is retrieved when loading font.
* src/ftinspect/panels/settingpanel.cpp,
src/ftinspect/panels/settingpanel.hpp: Uncomment functional code.
Remove `checkHintingMode` and `checkStemDarkening`. Applying of delayed
settings is taken care by the `MainGUI`. So emitting `fontReloadNeeded`
simply will do the work.
* src/ftinspect/maingui.cpp: Don't reset the cache so aggressively.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
-
6bf56f74
by Charlie Jiang
at 2022-09-04T23:19:26+08:00
[ftinspect] Add SFNT `name` table retrieving.
* src/ftinspect/engine/fontinfo.cpp, src/ftinspect/engine/fontinfo.hpp:
New files, add `SFNTName` to retrieve `name` table.
Conversions to `QString` from mainstream encodings are supported.
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Add `currentFontSFNTNames` and retrieve the `name` table when loading the
font. Also pass the SFNT name table when loading palettes.
* src/ftinspect/engine/mmgx.cpp, src/ftinspect/engine/paletteinfo.cpp:
Uncomment functional code to make use of the `name` table.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
14 changed files:
Changes:
src/ftinspect/CMakeLists.txt
... |
... |
@@ -24,6 +24,8 @@ add_executable(ftinspect |
24
|
24
|
"engine/fontfilemanager.cpp"
|
25
|
25
|
"engine/rendering.cpp"
|
26
|
26
|
"engine/paletteinfo.cpp"
|
|
27
|
+ "engine/mmgx.cpp"
|
|
28
|
+ "engine/fontinfo.cpp"
|
27
|
29
|
|
28
|
30
|
"glyphcomponents/glyphbitmap.cpp"
|
29
|
31
|
"glyphcomponents/glyphoutline.cpp"
|
... |
... |
@@ -40,6 +42,7 @@ add_executable(ftinspect |
40
|
42
|
"models/customcomboboxmodels.cpp"
|
41
|
43
|
|
42
|
44
|
"panels/settingpanel.cpp"
|
|
45
|
+ "panels/settingpanelmmgx.cpp"
|
43
|
46
|
"panels/singular.cpp"
|
44
|
47
|
)
|
45
|
48
|
target_link_libraries(ftinspect
|
src/ftinspect/engine/engine.cpp
... |
... |
@@ -11,6 +11,7 @@ |
11
|
11
|
#include <freetype/ftmodapi.h>
|
12
|
12
|
#include <freetype/ftdriver.h>
|
13
|
13
|
#include <freetype/ftlcdfil.h>
|
|
14
|
+#include <freetype/ftmm.h>
|
14
|
15
|
|
15
|
16
|
|
16
|
17
|
/////////////////////////////////////////////////////////////////////////////
|
... |
... |
@@ -327,6 +328,7 @@ Engine::loadFont(int fontIndex, |
327
|
328
|
ftSize_ = NULL;
|
328
|
329
|
curFamilyName_ = QString();
|
329
|
330
|
curStyleName_ = QString();
|
|
331
|
+ curSFNTNames_.clear();
|
330
|
332
|
}
|
331
|
333
|
else
|
332
|
334
|
{
|
... |
... |
@@ -342,7 +344,10 @@ Engine::loadFont(int fontIndex, |
342
|
344
|
fontType_ = FontType_TrueType;
|
343
|
345
|
else
|
344
|
346
|
fontType_ = FontType_Other;
|
|
347
|
+
|
|
348
|
+ SFNTName::get(this, curSFNTNames_);
|
345
|
349
|
loadPaletteInfos();
|
|
350
|
+ curMMGXState_ = MMGXAxisInfo::get(this, curMMGXAxes_);
|
346
|
351
|
}
|
347
|
352
|
|
348
|
353
|
curNumGlyphs_ = numGlyphs;
|
... |
... |
@@ -657,6 +662,19 @@ Engine::setStemDarkening(bool darkening) |
657
|
662
|
}
|
658
|
663
|
|
659
|
664
|
|
|
665
|
+void
|
|
666
|
+Engine::applyMMGXDesignCoords(FT_Fixed* coords,
|
|
667
|
+ size_t count)
|
|
668
|
+{
|
|
669
|
+ if (!ftSize_)
|
|
670
|
+ return;
|
|
671
|
+ if (count >= UINT_MAX)
|
|
672
|
+ count = UINT_MAX - 1;
|
|
673
|
+ FT_Set_Var_Design_Coordinates(ftSize_->face,
|
|
674
|
+ static_cast<unsigned>(count), coords);
|
|
675
|
+}
|
|
676
|
+
|
|
677
|
+
|
660
|
678
|
void
|
661
|
679
|
Engine::update()
|
662
|
680
|
{
|
... |
... |
@@ -834,8 +852,8 @@ Engine::loadPaletteInfos() |
834
|
852
|
// size never exceeds max val of ushort.
|
835
|
853
|
curPaletteInfos_.reserve(paletteData_.num_palettes);
|
836
|
854
|
for (int i = 0; i < paletteData_.num_palettes; ++i)
|
837
|
|
- curPaletteInfos_.emplace_back(ftFallbackFace_, paletteData_, i, nullptr);
|
838
|
|
- // no `NULL` here - we need `std::nullptr_t`
|
|
855
|
+ curPaletteInfos_.emplace_back(ftFallbackFace_, paletteData_, i,
|
|
856
|
+ &curSFNTNames_);
|
839
|
857
|
}
|
840
|
858
|
|
841
|
859
|
|
src/ftinspect/engine/engine.hpp
... |
... |
@@ -8,6 +8,8 @@ |
8
|
8
|
#include "fontfilemanager.hpp"
|
9
|
9
|
|
10
|
10
|
#include "paletteinfo.hpp"
|
|
11
|
+#include "fontinfo.hpp"
|
|
12
|
+#include "mmgx.hpp"
|
11
|
13
|
#include "rendering.hpp"
|
12
|
14
|
|
13
|
15
|
#include <memory>
|
... |
... |
@@ -119,6 +121,9 @@ public: |
119
|
121
|
std::vector<PaletteInfo>& currentFontPalettes() { return curPaletteInfos_; }
|
120
|
122
|
FT_Color* currentPalette() { return palette_; }
|
121
|
123
|
FT_Palette_Data& currentFontPaletteData() { return paletteData_; }
|
|
124
|
+ MMGXState currentFontMMGXState() { return curMMGXState_; }
|
|
125
|
+ std::vector<MMGXAxisInfo>& currentFontMMGXAxes() { return curMMGXAxes_; }
|
|
126
|
+ std::vector<SFNTName>& currentFontSFNTNames() { return curSFNTNames_; }
|
122
|
127
|
|
123
|
128
|
QString glyphName(int glyphIndex);
|
124
|
129
|
long numberOfFaces(int fontIndex);
|
... |
... |
@@ -183,7 +188,8 @@ public: |
183
|
188
|
void setTTInterpreterVersion(int version);
|
184
|
189
|
|
185
|
190
|
void setStemDarkening(bool darkening);
|
186
|
|
-
|
|
191
|
+ void applyMMGXDesignCoords(FT_Fixed* coords, size_t count);
|
|
192
|
+
|
187
|
193
|
//////// Misc
|
188
|
194
|
|
189
|
195
|
friend FT_Error faceRequester(FTC_FaceID,
|
... |
... |
@@ -200,11 +206,14 @@ private: |
200
|
206
|
|
201
|
207
|
// font info
|
202
|
208
|
int curFontIndex_ = -1;
|
|
209
|
+ int fontType_;
|
203
|
210
|
QString curFamilyName_;
|
204
|
211
|
QString curStyleName_;
|
205
|
212
|
int curNumGlyphs_ = -1;
|
206
|
213
|
std::vector<PaletteInfo> curPaletteInfos_;
|
207
|
|
- int fontType_;
|
|
214
|
+ MMGXState curMMGXState_ = MMGXState::NoMMGX;
|
|
215
|
+ std::vector<MMGXAxisInfo> curMMGXAxes_;
|
|
216
|
+ std::vector<SFNTName> curSFNTNames_;
|
208
|
217
|
|
209
|
218
|
// basic objects
|
210
|
219
|
FT_Library library_;
|
src/ftinspect/engine/fontinfo.cpp
|
1
|
+// fontinfo.cpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#include "fontinfo.hpp"
|
|
6
|
+
|
|
7
|
+#include "engine.hpp"
|
|
8
|
+
|
|
9
|
+#include <memory>
|
|
10
|
+#include <utility>
|
|
11
|
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
12
|
+#include <QTextCodec>
|
|
13
|
+#else
|
|
14
|
+#include <QStringConverter>
|
|
15
|
+#include <QByteArrayView>
|
|
16
|
+#endif
|
|
17
|
+#include <freetype/ftmodapi.h>
|
|
18
|
+#include <freetype/ttnameid.h>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+void
|
|
22
|
+SFNTName::get(Engine* engine,
|
|
23
|
+ std::vector<SFNTName>& list)
|
|
24
|
+{
|
|
25
|
+ auto face = engine->currentFallbackFtFace();
|
|
26
|
+ if (!face || !FT_IS_SFNT(face))
|
|
27
|
+ {
|
|
28
|
+ list.clear();
|
|
29
|
+ return;
|
|
30
|
+ }
|
|
31
|
+
|
|
32
|
+ auto newSize = FT_Get_Sfnt_Name_Count(face);
|
|
33
|
+ if (list.size() != static_cast<size_t>(newSize))
|
|
34
|
+ list.resize(newSize);
|
|
35
|
+
|
|
36
|
+ FT_SfntName sfntName;
|
|
37
|
+ FT_SfntLangTag langTag;
|
|
38
|
+ for (unsigned int i = 0; i < newSize; ++i)
|
|
39
|
+ {
|
|
40
|
+ FT_Get_Sfnt_Name(face, i, &sfntName);
|
|
41
|
+ auto& obj = list[i];
|
|
42
|
+ obj.platformID = sfntName.platform_id;
|
|
43
|
+ obj.encodingID = sfntName.encoding_id;
|
|
44
|
+ obj.languageID = sfntName.language_id;
|
|
45
|
+ obj.nameID = sfntName.name_id;
|
|
46
|
+
|
|
47
|
+ auto len = sfntName.string_len >= INT_MAX
|
|
48
|
+ ? INT_MAX - 1
|
|
49
|
+ : sfntName.string_len;
|
|
50
|
+ obj.strBuf = QByteArray(reinterpret_cast<const char*>(sfntName.string),
|
|
51
|
+ len);
|
|
52
|
+ obj.str = sfntNameToQString(sfntName, &obj.strValid);
|
|
53
|
+
|
|
54
|
+ if (obj.languageID >= 0x8000)
|
|
55
|
+ {
|
|
56
|
+ auto err = FT_Get_Sfnt_LangTag(face, obj.languageID, &langTag);
|
|
57
|
+ if (!err)
|
|
58
|
+ obj.langTag = utf16BEToQString(reinterpret_cast<char*>(langTag.string),
|
|
59
|
+ langTag.string_len);
|
|
60
|
+ }
|
|
61
|
+ }
|
|
62
|
+}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+QString
|
|
66
|
+SFNTName::sfntNameToQString(FT_SfntName const& sfntName,
|
|
67
|
+ bool* outSuccess)
|
|
68
|
+{
|
|
69
|
+ return sfntNameToQString(sfntName.platform_id, sfntName.encoding_id,
|
|
70
|
+ reinterpret_cast<char const*>(sfntName.string),
|
|
71
|
+ sfntName.string_len,
|
|
72
|
+ outSuccess);
|
|
73
|
+}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+QString
|
|
77
|
+SFNTName::sfntNameToQString(SFNTName const& sfntName, bool* outSuccess)
|
|
78
|
+{
|
|
79
|
+ return sfntNameToQString(sfntName.platformID, sfntName.encodingID,
|
|
80
|
+ sfntName.strBuf.data(), sfntName.strBuf.size(),
|
|
81
|
+ outSuccess);
|
|
82
|
+}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+QString
|
|
86
|
+SFNTName::sfntNameToQString(unsigned short platformID,
|
|
87
|
+ unsigned short encodingID,
|
|
88
|
+ char const* str,
|
|
89
|
+ size_t size,
|
|
90
|
+ bool* outSuccess)
|
|
91
|
+{
|
|
92
|
+ // TODO not complete.
|
|
93
|
+ if (size >= INT_MAX - 1)
|
|
94
|
+ return "";
|
|
95
|
+
|
|
96
|
+ if (outSuccess)
|
|
97
|
+ *outSuccess = true;
|
|
98
|
+
|
|
99
|
+ switch (platformID)
|
|
100
|
+ {
|
|
101
|
+ case TT_PLATFORM_APPLE_UNICODE:
|
|
102
|
+ // All UTF-16BE.
|
|
103
|
+ return utf16BEToQString(str, size);
|
|
104
|
+ case TT_PLATFORM_MACINTOSH:
|
|
105
|
+ if (encodingID == TT_MAC_ID_ROMAN)
|
|
106
|
+ return QString::fromLatin1(str, static_cast<int>(size));
|
|
107
|
+
|
|
108
|
+ if (outSuccess)
|
|
109
|
+ *outSuccess = false;
|
|
110
|
+ return "<encoding unsupported>";
|
|
111
|
+ case TT_PLATFORM_ISO:
|
|
112
|
+ switch (encodingID)
|
|
113
|
+ {
|
|
114
|
+ case TT_ISO_ID_7BIT_ASCII:
|
|
115
|
+ case TT_ISO_ID_8859_1:
|
|
116
|
+ return QString::fromLatin1(str, static_cast<int>(size));
|
|
117
|
+ case TT_ISO_ID_10646:
|
|
118
|
+ return utf16BEToQString(str, size);
|
|
119
|
+ default:
|
|
120
|
+ if (outSuccess)
|
|
121
|
+ *outSuccess = false;
|
|
122
|
+ return "<encoding unsupported>";
|
|
123
|
+ }
|
|
124
|
+ case TT_PLATFORM_MICROSOFT:
|
|
125
|
+ switch (encodingID)
|
|
126
|
+ {
|
|
127
|
+ /* TT_MS_ID_SYMBOL_CS is Unicode, similar to PID/EID=3/1 */
|
|
128
|
+ case TT_MS_ID_SYMBOL_CS:
|
|
129
|
+ case TT_MS_ID_UNICODE_CS:
|
|
130
|
+ case TT_MS_ID_UCS_4: // This is UTF-16LE as well, according to MS doc
|
|
131
|
+ return utf16BEToQString(str, size);
|
|
132
|
+
|
|
133
|
+ default:
|
|
134
|
+ if (outSuccess)
|
|
135
|
+ *outSuccess = false;
|
|
136
|
+ return "<encoding unsupported>";
|
|
137
|
+ }
|
|
138
|
+ }
|
|
139
|
+
|
|
140
|
+ if (outSuccess)
|
|
141
|
+ *outSuccess = false;
|
|
142
|
+ return "<platform unsupported>";
|
|
143
|
+}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
147
|
+QTextCodec* utf16BECodec = QTextCodec::codecForName("UTF-16BE");
|
|
148
|
+#else
|
|
149
|
+QStringDecoder utf16BECvt = (QStringDecoder(QStringDecoder::Utf16BE))(size);
|
|
150
|
+#endif
|
|
151
|
+
|
|
152
|
+QString
|
|
153
|
+SFNTName::utf16BEToQString(char const* str,
|
|
154
|
+ size_t size)
|
|
155
|
+{
|
|
156
|
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
157
|
+ if (size >= INT_MAX)
|
|
158
|
+ size = INT_MAX - 1;
|
|
159
|
+ return utf16BECodec->toUnicode(str, static_cast<int>(size));
|
|
160
|
+#else
|
|
161
|
+ return utf16BECvt(QByteArrayView(reinterpret_cast<char*>(str), size));
|
|
162
|
+#endif
|
|
163
|
+}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+// end of fontinfo.cpp |
src/ftinspect/engine/fontinfo.hpp
|
1
|
+// fontinfo.hpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#pragma once
|
|
6
|
+
|
|
7
|
+#include <set>
|
|
8
|
+#include <vector>
|
|
9
|
+#include <QByteArray>
|
|
10
|
+#include <QString>
|
|
11
|
+#include <freetype/freetype.h>
|
|
12
|
+#include <freetype/ftsnames.h>
|
|
13
|
+
|
|
14
|
+class Engine;
|
|
15
|
+struct SFNTName
|
|
16
|
+{
|
|
17
|
+ unsigned short nameID;
|
|
18
|
+ unsigned short platformID;
|
|
19
|
+ unsigned short encodingID;
|
|
20
|
+ unsigned short languageID;
|
|
21
|
+ QByteArray strBuf;
|
|
22
|
+ QString str;
|
|
23
|
+ QString langTag;
|
|
24
|
+ bool strValid = false;
|
|
25
|
+
|
|
26
|
+ static void get(Engine* engine,
|
|
27
|
+ std::vector<SFNTName>& list);
|
|
28
|
+ static QString sfntNameToQString(FT_SfntName const& sfntName,
|
|
29
|
+ bool* outSuccess = NULL);
|
|
30
|
+ static QString sfntNameToQString(SFNTName const& sfntName,
|
|
31
|
+ bool* outSuccess = NULL);
|
|
32
|
+ static QString sfntNameToQString(unsigned short platformID,
|
|
33
|
+ unsigned short encodingID,
|
|
34
|
+ char const* str, size_t size,
|
|
35
|
+ bool* outSuccess = NULL);
|
|
36
|
+ static QString utf16BEToQString(char const* str, size_t size);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+ friend bool
|
|
40
|
+ operator==(const SFNTName& lhs,
|
|
41
|
+ const SFNTName& rhs)
|
|
42
|
+ {
|
|
43
|
+ return lhs.nameID == rhs.nameID
|
|
44
|
+ && lhs.platformID == rhs.platformID
|
|
45
|
+ && lhs.encodingID == rhs.encodingID
|
|
46
|
+ && lhs.languageID == rhs.languageID
|
|
47
|
+ && lhs.strBuf == rhs.strBuf
|
|
48
|
+ && lhs.langTag == rhs.langTag;
|
|
49
|
+ }
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+ friend bool
|
|
53
|
+ operator!=(const SFNTName& lhs,
|
|
54
|
+ const SFNTName& rhs)
|
|
55
|
+ {
|
|
56
|
+ return !(lhs == rhs);
|
|
57
|
+ }
|
|
58
|
+};
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+// end of fontinfo.hpp |
src/ftinspect/engine/mmgx.cpp
|
1
|
+// mmgx.cpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#include "mmgx.hpp"
|
|
6
|
+
|
|
7
|
+#include "engine.hpp"
|
|
8
|
+
|
|
9
|
+#include <freetype/ftmm.h>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+MMGXState
|
|
13
|
+MMGXAxisInfo::get(Engine* engine,
|
|
14
|
+ std::vector<MMGXAxisInfo>& infos)
|
|
15
|
+{
|
|
16
|
+ auto face = engine->currentFallbackFtFace();
|
|
17
|
+ if (!face)
|
|
18
|
+ {
|
|
19
|
+ infos.clear();
|
|
20
|
+ return MMGXState::NoMMGX;
|
|
21
|
+ }
|
|
22
|
+
|
|
23
|
+ if (!FT_HAS_MULTIPLE_MASTERS(face))
|
|
24
|
+ {
|
|
25
|
+ infos.clear();
|
|
26
|
+ return MMGXState::NoMMGX;
|
|
27
|
+ }
|
|
28
|
+
|
|
29
|
+ FT_Multi_Master dummy;
|
|
30
|
+ auto error = FT_Get_Multi_Master(face, &dummy);
|
|
31
|
+ auto state = error ? MMGXState::GX_OVF : MMGXState::MM;
|
|
32
|
+
|
|
33
|
+ FT_MM_Var* mm;
|
|
34
|
+ if (FT_Get_MM_Var(face, &mm))
|
|
35
|
+ {
|
|
36
|
+ infos.clear();
|
|
37
|
+ return state;
|
|
38
|
+ }
|
|
39
|
+
|
|
40
|
+ infos.resize(mm->num_axis);
|
|
41
|
+
|
|
42
|
+ auto& sfnt = engine->currentFontSFNTNames();
|
|
43
|
+ for (unsigned int i = 0; i < mm->num_axis; ++i)
|
|
44
|
+ {
|
|
45
|
+ auto& axis = mm->axis[i];
|
|
46
|
+ auto& info = infos[i];
|
|
47
|
+ info.maximum = axis.maximum / 65536.0;
|
|
48
|
+ info.minimum = axis.minimum / 65536.0;
|
|
49
|
+ info.def = axis.def / 65536.0;
|
|
50
|
+ info.tag = axis.tag;
|
|
51
|
+ info.isMM = state == MMGXState::MM;
|
|
52
|
+
|
|
53
|
+ unsigned int flags = 0;
|
|
54
|
+ FT_Get_Var_Axis_Flags(mm, i, &flags);
|
|
55
|
+ info.hidden = (flags & FT_VAR_AXIS_FLAG_HIDDEN) != 0;
|
|
56
|
+
|
|
57
|
+ auto nameSet = false;
|
|
58
|
+ if (state == MMGXState::GX_OVF)
|
|
59
|
+ {
|
|
60
|
+ auto strid = mm->axis[i].strid;
|
|
61
|
+ for (auto& obj : sfnt)
|
|
62
|
+ {
|
|
63
|
+ if (obj.nameID == strid && obj.strValid)
|
|
64
|
+ {
|
|
65
|
+ info.name = obj.str;
|
|
66
|
+ nameSet = true;
|
|
67
|
+ break;
|
|
68
|
+ }
|
|
69
|
+ }
|
|
70
|
+ }
|
|
71
|
+
|
|
72
|
+ // XXX security flaw
|
|
73
|
+ if (!nameSet)
|
|
74
|
+ info.name = QString(axis.name);
|
|
75
|
+ }
|
|
76
|
+
|
|
77
|
+ FT_Done_MM_Var(face->glyph->library, mm);
|
|
78
|
+
|
|
79
|
+ return state;
|
|
80
|
+}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+// end of mmgx.cpp |
src/ftinspect/engine/mmgx.hpp
|
1
|
+// mmgx.hpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#pragma once
|
|
6
|
+
|
|
7
|
+#include <vector>
|
|
8
|
+#include <QString>
|
|
9
|
+
|
|
10
|
+class Engine;
|
|
11
|
+
|
|
12
|
+enum class MMGXState
|
|
13
|
+{
|
|
14
|
+ NoMMGX,
|
|
15
|
+ MM, // Adobe MM
|
|
16
|
+ GX_OVF, // GX or OpenType variable fonts
|
|
17
|
+};
|
|
18
|
+
|
|
19
|
+struct MMGXAxisInfo
|
|
20
|
+{
|
|
21
|
+ QString name;
|
|
22
|
+ unsigned long tag;
|
|
23
|
+
|
|
24
|
+ double minimum;
|
|
25
|
+ double maximum;
|
|
26
|
+ double def;
|
|
27
|
+
|
|
28
|
+ bool hidden;
|
|
29
|
+ bool isMM;
|
|
30
|
+
|
|
31
|
+ static MMGXState get(Engine* engine, std::vector<MMGXAxisInfo>& infos);
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+ friend bool
|
|
35
|
+ operator==(const MMGXAxisInfo& lhs,
|
|
36
|
+ const MMGXAxisInfo& rhs)
|
|
37
|
+ {
|
|
38
|
+ return lhs.name == rhs.name
|
|
39
|
+ && lhs.tag == rhs.tag
|
|
40
|
+ && lhs.minimum == rhs.minimum
|
|
41
|
+ && lhs.maximum == rhs.maximum
|
|
42
|
+ && lhs.def == rhs.def
|
|
43
|
+ && lhs.hidden == rhs.hidden
|
|
44
|
+ && lhs.isMM == rhs.isMM;
|
|
45
|
+ }
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+ friend bool
|
|
49
|
+ operator!=(const MMGXAxisInfo& lhs,
|
|
50
|
+ const MMGXAxisInfo& rhs)
|
|
51
|
+ {
|
|
52
|
+ return !(lhs == rhs);
|
|
53
|
+ }
|
|
54
|
+};
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+// end of mmgx.hpp |
src/ftinspect/engine/paletteinfo.cpp
... |
... |
@@ -4,7 +4,7 @@ |
4
|
4
|
|
5
|
5
|
#include "paletteinfo.hpp"
|
6
|
6
|
|
7
|
|
-//#include "fontinfo.hpp"
|
|
7
|
+#include "fontinfo.hpp"
|
8
|
8
|
|
9
|
9
|
PaletteInfo::PaletteInfo(FT_Face face,
|
10
|
10
|
FT_Palette_Data& data,
|
... |
... |
@@ -15,15 +15,15 @@ PaletteInfo::PaletteInfo(FT_Face face, |
15
|
15
|
if (sfntNames && data.palette_name_ids)
|
16
|
16
|
{
|
17
|
17
|
auto id = data.palette_name_ids[index];
|
18
|
|
- name = "(unsupported)";
|
19
|
|
- //for (auto& obj : *sfntNames)
|
20
|
|
- //{
|
21
|
|
- // if (obj.nameID == id && obj.strValid)
|
22
|
|
- // {
|
23
|
|
- // name = obj.str;
|
24
|
|
- // break;
|
25
|
|
- // }
|
26
|
|
- //}
|
|
18
|
+ name = "(invalid)";
|
|
19
|
+ for (auto& obj : *sfntNames)
|
|
20
|
+ {
|
|
21
|
+ if (obj.nameID == id && obj.strValid)
|
|
22
|
+ {
|
|
23
|
+ name = obj.str;
|
|
24
|
+ break;
|
|
25
|
+ }
|
|
26
|
+ }
|
27
|
27
|
}
|
28
|
28
|
else
|
29
|
29
|
name = "(unnamed)";
|
src/ftinspect/maingui.cpp
... |
... |
@@ -180,7 +180,7 @@ MainGUI::repaintCurrentTab() |
180
|
180
|
void
|
181
|
181
|
MainGUI::reloadCurrentTabFont()
|
182
|
182
|
{
|
183
|
|
- engine_->resetCache();
|
|
183
|
+ settingPanel_->applyDelayedSettings(); // This will reset the cache.
|
184
|
184
|
applySettings();
|
185
|
185
|
auto index = tabWidget_->currentIndex();
|
186
|
186
|
if (index >= 0 && static_cast<size_t>(index) < tabs_.size())
|
... |
... |
@@ -192,7 +192,6 @@ void |
192
|
192
|
MainGUI::applySettings()
|
193
|
193
|
{
|
194
|
194
|
settingPanel_->applySettings();
|
195
|
|
- settingPanel_->applyDelayedSettings();
|
196
|
195
|
}
|
197
|
196
|
|
198
|
197
|
|
src/ftinspect/meson.build
... |
... |
@@ -25,6 +25,8 @@ if qt5_dep.found() |
25
|
25
|
'engine/fontfilemanager.cpp',
|
26
|
26
|
'engine/rendering.cpp',
|
27
|
27
|
'engine/paletteinfo.cpp',
|
|
28
|
+ 'engine/mmgx.cpp',
|
|
29
|
+ 'engine/fontinfo.cpp',
|
28
|
30
|
|
29
|
31
|
'glyphcomponents/glyphbitmap.cpp',
|
30
|
32
|
'glyphcomponents/glyphoutline.cpp',
|
... |
... |
@@ -41,6 +43,7 @@ if qt5_dep.found() |
41
|
43
|
'models/customcomboboxmodels.cpp',
|
42
|
44
|
|
43
|
45
|
'panels/settingpanel.cpp',
|
|
46
|
+ 'panels/settingpanelmmgx.cpp',
|
44
|
47
|
'panels/singular.cpp',
|
45
|
48
|
|
46
|
49
|
'ftinspect.cpp',
|
... |
... |
@@ -58,6 +61,7 @@ if qt5_dep.found() |
58
|
61
|
'maingui.hpp',
|
59
|
62
|
'models/customcomboboxmodels.hpp',
|
60
|
63
|
'panels/settingpanel.hpp',
|
|
64
|
+ 'panels/settingpanelmmgx.hpp',
|
61
|
65
|
'panels/singular.hpp',
|
62
|
66
|
],
|
63
|
67
|
dependencies: qt5_dep)
|
src/ftinspect/panels/settingpanel.cpp
... |
... |
@@ -99,16 +99,6 @@ SettingPanel::checkHinting() |
99
|
99
|
}
|
100
|
100
|
|
101
|
101
|
|
102
|
|
-void
|
103
|
|
-SettingPanel::checkHintingMode()
|
104
|
|
-{
|
105
|
|
- //if (!comparatorMode_)
|
106
|
|
- applyDelayedSettings();
|
107
|
|
-
|
108
|
|
- emit fontReloadNeeded();
|
109
|
|
-}
|
110
|
|
-
|
111
|
|
-
|
112
|
102
|
void
|
113
|
103
|
SettingPanel::checkAutoHinting()
|
114
|
104
|
{
|
... |
... |
@@ -193,16 +183,6 @@ SettingPanel::checkPalette() |
193
|
183
|
}
|
194
|
184
|
|
195
|
185
|
|
196
|
|
-void
|
197
|
|
-SettingPanel::checkStemDarkening()
|
198
|
|
-{
|
199
|
|
- //if (!comparatorMode_)
|
200
|
|
- applyDelayedSettings();
|
201
|
|
-
|
202
|
|
- emit fontReloadNeeded();
|
203
|
|
-}
|
204
|
|
-
|
205
|
|
-
|
206
|
186
|
void
|
207
|
187
|
SettingPanel::openBackgroundPicker()
|
208
|
188
|
{
|
... |
... |
@@ -339,7 +319,7 @@ SettingPanel::onFontChanged() |
339
|
319
|
paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked()
|
340
|
320
|
&& paletteComboBox_->count() > 0);
|
341
|
321
|
populatePalettes();
|
342
|
|
- //mmgxPanel_->reloadFont();
|
|
322
|
+ mmgxPanel_->reloadFont();
|
343
|
323
|
blockSignals(blockState);
|
344
|
324
|
|
345
|
325
|
// Place this after `blockSignals` to let the signals emitted normally
|
... |
... |
@@ -389,7 +369,7 @@ SettingPanel::applySettings() |
389
|
369
|
|
390
|
370
|
engine_->renderingEngine()->setForeground(foregroundColor_.rgba());
|
391
|
371
|
engine_->renderingEngine()->setBackground(backgroundColor_.rgba());
|
392
|
|
- //mmgxPanel_->applySettings();
|
|
372
|
+ mmgxPanel_->applySettings();
|
393
|
373
|
}
|
394
|
374
|
|
395
|
375
|
|
... |
... |
@@ -481,8 +461,7 @@ SettingPanel::createLayout() |
481
|
461
|
gammaLabel_->setBuddy(gammaSlider_);
|
482
|
462
|
gammaValueLabel_ = new QLabel(this);
|
483
|
463
|
|
484
|
|
- // TODO: MM/GX
|
485
|
|
- mmgxPanel_ = new QWidget(this);
|
|
464
|
+ mmgxPanel_ = new SettingPanelMMGX(this, engine_);
|
486
|
465
|
|
487
|
466
|
backgroundButton_ = new QPushButton(tr("Background"), this);
|
488
|
467
|
foregroundButton_ = new QPushButton(tr("Foreground"), this);
|
... |
... |
@@ -622,7 +601,7 @@ SettingPanel::createConnections() |
622
|
601
|
// use `qOverload` here to prevent ambiguity.
|
623
|
602
|
connect(hintingModeComboBox_,
|
624
|
603
|
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
625
|
|
- this, &SettingPanel::checkHintingMode);
|
|
604
|
+ this, &SettingPanel::fontReloadNeeded);
|
626
|
605
|
connect(antiAliasingComboBox_,
|
627
|
606
|
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
628
|
607
|
this, &SettingPanel::checkAntiAliasing);
|
... |
... |
@@ -656,7 +635,7 @@ SettingPanel::createConnections() |
656
|
635
|
connect(embeddedBitmapCheckBox_, &QCheckBox::clicked,
|
657
|
636
|
this, &SettingPanel::fontReloadNeeded);
|
658
|
637
|
connect(stemDarkeningCheckBox_, &QCheckBox::clicked,
|
659
|
|
- this, &SettingPanel::checkStemDarkening);
|
|
638
|
+ this, &SettingPanel::fontReloadNeeded);
|
660
|
639
|
connect(colorLayerCheckBox_, &QCheckBox::clicked,
|
661
|
640
|
this, &SettingPanel::checkPalette);
|
662
|
641
|
|
... |
... |
@@ -664,6 +643,9 @@ SettingPanel::createConnections() |
664
|
643
|
this, &SettingPanel::openBackgroundPicker);
|
665
|
644
|
connect(foregroundButton_, &QPushButton::clicked,
|
666
|
645
|
this, &SettingPanel::openForegroundPicker);
|
|
646
|
+
|
|
647
|
+ connect(mmgxPanel_, &SettingPanelMMGX::mmgxCoordsChanged,
|
|
648
|
+ this, &SettingPanel::fontReloadNeeded);
|
667
|
649
|
}
|
668
|
650
|
|
669
|
651
|
|
src/ftinspect/panels/settingpanel.hpp
... |
... |
@@ -6,6 +6,7 @@ |
6
|
6
|
|
7
|
7
|
#include "../engine/engine.hpp"
|
8
|
8
|
#include "../models/customcomboboxmodels.hpp"
|
|
9
|
+#include "settingpanelmmgx.hpp"
|
9
|
10
|
|
10
|
11
|
#include <QWidget>
|
11
|
12
|
#include <QTabWidget>
|
... |
... |
@@ -54,8 +55,7 @@ private: |
54
|
55
|
|
55
|
56
|
QWidget* generalTab_;
|
56
|
57
|
QWidget* hintingRenderingTab_;
|
57
|
|
- //SettingPanelMMGX* mmgxPanel_;
|
58
|
|
- QWidget* mmgxPanel_;
|
|
58
|
+ SettingPanelMMGX* mmgxPanel_;
|
59
|
59
|
|
60
|
60
|
QLabel* gammaLabel_;
|
61
|
61
|
QLabel* gammaValueLabel_;
|
... |
... |
@@ -113,11 +113,9 @@ private: |
113
|
113
|
|
114
|
114
|
void checkAllSettings();
|
115
|
115
|
void checkHinting();
|
116
|
|
- void checkHintingMode();
|
117
|
116
|
void checkAutoHinting();
|
118
|
117
|
void checkAntiAliasing();
|
119
|
118
|
void checkPalette();
|
120
|
|
- void checkStemDarkening();
|
121
|
119
|
|
122
|
120
|
void openBackgroundPicker();
|
123
|
121
|
void openForegroundPicker();
|
src/ftinspect/panels/settingpanelmmgx.cpp
|
1
|
+// settingpanelmmgx.cpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#include "settingpanelmmgx.hpp"
|
|
6
|
+
|
|
7
|
+#include <QScrollBar>
|
|
8
|
+
|
|
9
|
+#include "../engine/engine.hpp"
|
|
10
|
+#include "../uihelper.hpp"
|
|
11
|
+
|
|
12
|
+SettingPanelMMGX::SettingPanelMMGX(QWidget* parent,
|
|
13
|
+ Engine* engine)
|
|
14
|
+: QWidget(parent),
|
|
15
|
+ engine_(engine)
|
|
16
|
+{
|
|
17
|
+ createLayout();
|
|
18
|
+ createConnections();
|
|
19
|
+}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+void
|
|
23
|
+SettingPanelMMGX::reloadFont()
|
|
24
|
+{
|
|
25
|
+ setEnabled(engine_->currentFontMMGXState() != MMGXState::NoMMGX);
|
|
26
|
+ if (currentAxes_ == engine_->currentFontMMGXAxes())
|
|
27
|
+ return;
|
|
28
|
+
|
|
29
|
+ currentAxes_ = engine_->currentFontMMGXAxes();
|
|
30
|
+
|
|
31
|
+ auto newSize = currentAxes_.size();
|
|
32
|
+ auto oldSize = itemWidgets_.size();
|
|
33
|
+ auto minSize = std::min(newSize, oldSize);
|
|
34
|
+
|
|
35
|
+ // This won't trigger unexpected updating since signals are blocked
|
|
36
|
+ for (size_t i = 0; i < minSize; ++i)
|
|
37
|
+ itemWidgets_[i]->updateInfo(currentAxes_[i]);
|
|
38
|
+
|
|
39
|
+ if (newSize < oldSize)
|
|
40
|
+ {
|
|
41
|
+ for (size_t i = newSize; i < oldSize; ++i)
|
|
42
|
+ {
|
|
43
|
+ auto w = itemWidgets_[i];
|
|
44
|
+ disconnect(w);
|
|
45
|
+ listLayout_->removeWidget(w);
|
|
46
|
+ delete w;
|
|
47
|
+ }
|
|
48
|
+ itemWidgets_.resize(newSize);
|
|
49
|
+ }
|
|
50
|
+ else if (newSize > oldSize)
|
|
51
|
+ {
|
|
52
|
+ itemWidgets_.resize(newSize);
|
|
53
|
+ for (size_t i = oldSize; i < newSize; ++i)
|
|
54
|
+ {
|
|
55
|
+ auto w = new MMGXSettingItem(this);
|
|
56
|
+ itemWidgets_[i] = w;
|
|
57
|
+ w->updateInfo(currentAxes_[i]);
|
|
58
|
+ listLayout_->addWidget(w);
|
|
59
|
+ connect(w, &MMGXSettingItem::valueChanged,
|
|
60
|
+ [this, i] { itemChanged(i); });
|
|
61
|
+ }
|
|
62
|
+ }
|
|
63
|
+ checkHidden();
|
|
64
|
+ retrieveValues();
|
|
65
|
+ applySettings();
|
|
66
|
+}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+void
|
|
70
|
+SettingPanelMMGX::applySettings()
|
|
71
|
+{
|
|
72
|
+ engine_->reloadFont();
|
|
73
|
+ engine_->applyMMGXDesignCoords(currentValues_.data(),
|
|
74
|
+ currentValues_.size());
|
|
75
|
+}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+void
|
|
79
|
+SettingPanelMMGX::checkHidden()
|
|
80
|
+{
|
|
81
|
+ if (itemWidgets_.size() < currentAxes_.size())
|
|
82
|
+ return; // This should never happen!
|
|
83
|
+ for (int i = 0; static_cast<size_t>(i) < currentAxes_.size(); ++i)
|
|
84
|
+ itemWidgets_[i]->setVisible(showHiddenCheckBox_->isChecked()
|
|
85
|
+ || !currentAxes_[i].hidden);
|
|
86
|
+}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+void
|
|
90
|
+SettingPanelMMGX::createLayout()
|
|
91
|
+{
|
|
92
|
+ showHiddenCheckBox_ = new QCheckBox(tr("Show Hidden"), this);
|
|
93
|
+ groupingCheckBox_ = new QCheckBox(tr("Grouping"), this);
|
|
94
|
+ resetDefaultButton_ = new QPushButton(tr("Reset Default"), this);
|
|
95
|
+ itemsListWidget_ = new QWidget(this);
|
|
96
|
+ scrollArea_ = new UnboundScrollArea(this);
|
|
97
|
+
|
|
98
|
+ scrollArea_->setWidget(itemsListWidget_);
|
|
99
|
+ scrollArea_->setWidgetResizable(true);
|
|
100
|
+ itemsListWidget_->setAutoFillBackground(false);
|
|
101
|
+
|
|
102
|
+ mainLayout_ = new QVBoxLayout;
|
|
103
|
+ listLayout_ = new QVBoxLayout;
|
|
104
|
+ listWrapperLayout_ = new QVBoxLayout;
|
|
105
|
+
|
|
106
|
+ listLayout_->setSpacing(0);
|
|
107
|
+ listLayout_->setContentsMargins(0, 0, 0, 0);
|
|
108
|
+ itemsListWidget_->setContentsMargins(0, 0, 0, 0);
|
|
109
|
+
|
|
110
|
+ itemsListWidget_->setLayout(listWrapperLayout_);
|
|
111
|
+
|
|
112
|
+ listWrapperLayout_->addLayout(listLayout_);
|
|
113
|
+ listWrapperLayout_->addStretch(1);
|
|
114
|
+
|
|
115
|
+ mainLayout_->addWidget(showHiddenCheckBox_);
|
|
116
|
+ mainLayout_->addWidget(groupingCheckBox_);
|
|
117
|
+ mainLayout_->addWidget(resetDefaultButton_);
|
|
118
|
+ mainLayout_->addWidget(scrollArea_, 1);
|
|
119
|
+
|
|
120
|
+ setLayout(mainLayout_);
|
|
121
|
+}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+void
|
|
125
|
+SettingPanelMMGX::createConnections()
|
|
126
|
+{
|
|
127
|
+ connect(showHiddenCheckBox_, &QCheckBox::clicked,
|
|
128
|
+ this, &SettingPanelMMGX::checkHidden);
|
|
129
|
+ connect(resetDefaultButton_, &QCheckBox::clicked,
|
|
130
|
+ this, &SettingPanelMMGX::resetDefaultClicked);
|
|
131
|
+ connect(groupingCheckBox_, &QCheckBox::clicked,
|
|
132
|
+ this, &SettingPanelMMGX::checkGrouping);
|
|
133
|
+}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+void
|
|
137
|
+SettingPanelMMGX::retrieveValues()
|
|
138
|
+{
|
|
139
|
+ currentValues_.resize(currentAxes_.size());
|
|
140
|
+ for (unsigned i = 0; i < currentAxes_.size(); ++i)
|
|
141
|
+ currentValues_[i] = itemWidgets_[i]->value();
|
|
142
|
+}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+void
|
|
146
|
+SettingPanelMMGX::itemChanged(size_t index)
|
|
147
|
+{
|
|
148
|
+ if (groupingCheckBox_->isChecked()
|
|
149
|
+ && index < currentAxes_.size() && index < itemWidgets_.size())
|
|
150
|
+ {
|
|
151
|
+ auto tag = currentAxes_[index].tag;
|
|
152
|
+ auto value = itemWidgets_[index]->value();
|
|
153
|
+ for (size_t i = 0; i < itemWidgets_.size(); ++i)
|
|
154
|
+ if (i != index && currentAxes_[i].tag == tag)
|
|
155
|
+ itemWidgets_[i]->setValue(value);
|
|
156
|
+ }
|
|
157
|
+
|
|
158
|
+ retrieveValues();
|
|
159
|
+ emit mmgxCoordsChanged();
|
|
160
|
+}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+void
|
|
164
|
+SettingPanelMMGX::resetDefaultClicked()
|
|
165
|
+{
|
|
166
|
+ for (auto w : itemWidgets_)
|
|
167
|
+ w->resetDefault();
|
|
168
|
+
|
|
169
|
+ retrieveValues();
|
|
170
|
+ emit mmgxCoordsChanged();
|
|
171
|
+}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+void
|
|
175
|
+SettingPanelMMGX::checkGrouping()
|
|
176
|
+{
|
|
177
|
+ if (!groupingCheckBox_->isChecked())
|
|
178
|
+ return;
|
|
179
|
+ auto maxIndex = std::max(itemWidgets_.size(), currentAxes_.size());
|
|
180
|
+ for (size_t i = maxIndex - 1; ; --i)
|
|
181
|
+ {
|
|
182
|
+ if (!currentAxes_[i].hidden)
|
|
183
|
+ {
|
|
184
|
+ auto tag = currentAxes_[i].tag;
|
|
185
|
+ auto value = itemWidgets_[i]->value();
|
|
186
|
+ for (size_t j = 0; j < maxIndex; ++j)
|
|
187
|
+ if (j != i && currentAxes_[j].tag == tag)
|
|
188
|
+ itemWidgets_[j]->setValue(value);
|
|
189
|
+ }
|
|
190
|
+
|
|
191
|
+ if (i == 0)
|
|
192
|
+ break;
|
|
193
|
+ }
|
|
194
|
+
|
|
195
|
+ retrieveValues();
|
|
196
|
+ emit mmgxCoordsChanged();
|
|
197
|
+}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+MMGXSettingItem::MMGXSettingItem(QWidget* parent)
|
|
201
|
+: QFrame(parent)
|
|
202
|
+{
|
|
203
|
+ createLayout();
|
|
204
|
+ createConnections();
|
|
205
|
+}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+void
|
|
209
|
+MMGXSettingItem::updateInfo(MMGXAxisInfo& info)
|
|
210
|
+{
|
|
211
|
+ axisInfo_ = info;
|
|
212
|
+ valueValidator_->setRange(info.minimum, info.maximum, 10);
|
|
213
|
+
|
|
214
|
+ if (info.hidden)
|
|
215
|
+ nameLabel_->setText("<i>" + info.name + "</i>");
|
|
216
|
+ else
|
|
217
|
+ nameLabel_->setText(info.name);
|
|
218
|
+
|
|
219
|
+ // To keep things simple, we will use 1/1024 of the span between the min and
|
|
220
|
+ // max as one step on the slider.
|
|
221
|
+
|
|
222
|
+ slider_->setMinimum(0);
|
|
223
|
+ slider_->setTickInterval(1);
|
|
224
|
+ slider_->setMaximum(1024);
|
|
225
|
+
|
|
226
|
+ resetDefault();
|
|
227
|
+}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+void
|
|
231
|
+MMGXSettingItem::setValue(FT_Fixed value)
|
|
232
|
+{
|
|
233
|
+ actualValue_ = value;
|
|
234
|
+ updateSlider();
|
|
235
|
+ updateLineEdit();
|
|
236
|
+}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+void
|
|
240
|
+MMGXSettingItem::resetDefault()
|
|
241
|
+{
|
|
242
|
+ setValue(static_cast<FT_Fixed>(axisInfo_.def * 65536.0));
|
|
243
|
+}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+void
|
|
247
|
+MMGXSettingItem::createLayout()
|
|
248
|
+{
|
|
249
|
+ nameLabel_ = new QLabel(this);
|
|
250
|
+
|
|
251
|
+ // 1/1024 = 0.0009765625
|
|
252
|
+ valueValidator_ = new QDoubleValidator(0, 0, 10, this);
|
|
253
|
+ valueValidator_->setNotation(QDoubleValidator::StandardNotation);
|
|
254
|
+
|
|
255
|
+ valueLineEdit_ = new QLineEdit("0", this);
|
|
256
|
+ valueLineEdit_->setValidator(valueValidator_);
|
|
257
|
+
|
|
258
|
+ slider_ = new QSlider(this);
|
|
259
|
+ slider_->setOrientation(Qt::Horizontal);
|
|
260
|
+
|
|
261
|
+ resetDefaultButton_ = new QPushButton(this);
|
|
262
|
+ resetDefaultButton_->setText(tr("Def"));
|
|
263
|
+ setButtonNarrowest(resetDefaultButton_);
|
|
264
|
+
|
|
265
|
+ nameLabel_->setToolTip(tr("Axis name or tag"));
|
|
266
|
+ slider_->setToolTip(
|
|
267
|
+ tr("Axis value (max precision: 1/1024 of the value range)"));
|
|
268
|
+ valueLineEdit_->setToolTip(tr("Axis value"));
|
|
269
|
+ resetDefaultButton_->setToolTip(tr("Reset axis to default"));
|
|
270
|
+
|
|
271
|
+ mainLayout_ = new QGridLayout();
|
|
272
|
+
|
|
273
|
+ mainLayout_->addWidget(nameLabel_, 0, 0, 1, 2);
|
|
274
|
+ mainLayout_->addWidget(slider_, 1, 0, 1, 2);
|
|
275
|
+ mainLayout_->addWidget(valueLineEdit_, 2, 0, 1, 1, Qt::AlignVCenter);
|
|
276
|
+ mainLayout_->addWidget(resetDefaultButton_, 2, 1, 1, 1, Qt::AlignVCenter);
|
|
277
|
+
|
|
278
|
+ mainLayout_->setSpacing(4);
|
|
279
|
+ mainLayout_->setContentsMargins(4, 4, 4, 4);
|
|
280
|
+ setContentsMargins(0, 0, 0, 0);
|
|
281
|
+ setLayout(mainLayout_);
|
|
282
|
+ setFrameShape(StyledPanel);
|
|
283
|
+}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+void
|
|
287
|
+MMGXSettingItem::createConnections()
|
|
288
|
+{
|
|
289
|
+ connect(slider_, &QSlider::valueChanged,
|
|
290
|
+ this, &MMGXSettingItem::sliderValueChanged);
|
|
291
|
+ connect(valueLineEdit_, &QLineEdit::editingFinished,
|
|
292
|
+ this, &MMGXSettingItem::lineEditChanged);
|
|
293
|
+ connect(resetDefaultButton_, &QToolButton::clicked,
|
|
294
|
+ this, &MMGXSettingItem::resetDefaultSingle);
|
|
295
|
+}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+void
|
|
299
|
+MMGXSettingItem::sliderValueChanged()
|
|
300
|
+{
|
|
301
|
+ auto value = slider_->value() / 1024.0
|
|
302
|
+ * (axisInfo_.maximum - axisInfo_.minimum)
|
|
303
|
+ + axisInfo_.minimum;
|
|
304
|
+ actualValue_ = static_cast<FT_Fixed>(value * 65536.0);
|
|
305
|
+
|
|
306
|
+ if (axisInfo_.isMM)
|
|
307
|
+ actualValue_ = FT_RoundFix(actualValue_);
|
|
308
|
+
|
|
309
|
+ updateLineEdit();
|
|
310
|
+ emit valueChanged();
|
|
311
|
+}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+void
|
|
315
|
+MMGXSettingItem::lineEditChanged()
|
|
316
|
+{
|
|
317
|
+ bool succ = false;
|
|
318
|
+ auto newValue = valueLineEdit_->text().toDouble(&succ);
|
|
319
|
+ if (!succ || newValue > axisInfo_.maximum || newValue < axisInfo_.minimum)
|
|
320
|
+ {
|
|
321
|
+ updateLineEdit();
|
|
322
|
+ return;
|
|
323
|
+ }
|
|
324
|
+
|
|
325
|
+ actualValue_ = static_cast<FT_Fixed>(newValue / 65536.0);
|
|
326
|
+
|
|
327
|
+ updateSlider();
|
|
328
|
+ emit valueChanged();
|
|
329
|
+}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+void
|
|
333
|
+MMGXSettingItem::updateLineEdit()
|
|
334
|
+{
|
|
335
|
+ QSignalBlocker blocker(valueLineEdit_);
|
|
336
|
+ valueLineEdit_->setText(QString::number(actualValue_ / 65536.0));
|
|
337
|
+}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+void
|
|
341
|
+MMGXSettingItem::updateSlider()
|
|
342
|
+{
|
|
343
|
+ QSignalBlocker blocker(slider_);
|
|
344
|
+ slider_->setValue(
|
|
345
|
+ static_cast<int>((actualValue_ / 65536.0 - axisInfo_.minimum)
|
|
346
|
+ / (axisInfo_.maximum - axisInfo_.minimum)
|
|
347
|
+ * 1024));
|
|
348
|
+}
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+void
|
|
352
|
+MMGXSettingItem::resetDefaultSingle()
|
|
353
|
+{
|
|
354
|
+ resetDefault();
|
|
355
|
+ emit valueChanged();
|
|
356
|
+}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+// end of settingpanelmmgx.cpp |
src/ftinspect/panels/settingpanelmmgx.hpp
|
1
|
+// settingpanelmmgx.hpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#pragma once
|
|
6
|
+
|
|
7
|
+#include "../engine/mmgx.hpp"
|
|
8
|
+#include "../widgets/customwidgets.hpp"
|
|
9
|
+
|
|
10
|
+#include <QWidget>
|
|
11
|
+#include <QGridLayout>
|
|
12
|
+#include <QBoxLayout>
|
|
13
|
+#include <QCheckBox>
|
|
14
|
+#include <QScrollArea>
|
|
15
|
+#include <QLineEdit>
|
|
16
|
+#include <QSlider>
|
|
17
|
+#include <QFrame>
|
|
18
|
+#include <QPushButton>
|
|
19
|
+#include <QToolButton>
|
|
20
|
+#include <QLabel>
|
|
21
|
+#include <QDoubleValidator>
|
|
22
|
+
|
|
23
|
+#include <freetype/fttypes.h>
|
|
24
|
+
|
|
25
|
+class Engine;
|
|
26
|
+
|
|
27
|
+class MMGXSettingItem;
|
|
28
|
+class SettingPanelMMGX
|
|
29
|
+: public QWidget
|
|
30
|
+{
|
|
31
|
+ Q_OBJECT
|
|
32
|
+public:
|
|
33
|
+ SettingPanelMMGX(QWidget* parent, Engine* engine);
|
|
34
|
+ ~SettingPanelMMGX() override = default;
|
|
35
|
+
|
|
36
|
+ void reloadFont();
|
|
37
|
+ void applySettings();
|
|
38
|
+ void checkHidden();
|
|
39
|
+ std::vector<FT_Fixed>& mmgxCoords() { return currentValues_; }
|
|
40
|
+
|
|
41
|
+signals:
|
|
42
|
+ void mmgxCoordsChanged();
|
|
43
|
+
|
|
44
|
+private:
|
|
45
|
+ Engine* engine_;
|
|
46
|
+
|
|
47
|
+ QCheckBox* showHiddenCheckBox_;
|
|
48
|
+ QCheckBox* groupingCheckBox_;
|
|
49
|
+ QPushButton* resetDefaultButton_;
|
|
50
|
+ QWidget* itemsListWidget_;
|
|
51
|
+ UnboundScrollArea* scrollArea_;
|
|
52
|
+ std::vector<MMGXSettingItem*> itemWidgets_;
|
|
53
|
+
|
|
54
|
+ QVBoxLayout* mainLayout_;
|
|
55
|
+ QVBoxLayout* listLayout_;
|
|
56
|
+ QVBoxLayout* listWrapperLayout_;
|
|
57
|
+
|
|
58
|
+ std::vector<FT_Fixed> currentValues_;
|
|
59
|
+ std::vector<MMGXAxisInfo> currentAxes_;
|
|
60
|
+
|
|
61
|
+ void createLayout();
|
|
62
|
+ void createConnections();
|
|
63
|
+
|
|
64
|
+ void retrieveValues();
|
|
65
|
+ void itemChanged(size_t index);
|
|
66
|
+ void resetDefaultClicked();
|
|
67
|
+ void checkGrouping();
|
|
68
|
+};
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+class MMGXSettingItem
|
|
72
|
+: public QFrame
|
|
73
|
+{
|
|
74
|
+ Q_OBJECT
|
|
75
|
+public:
|
|
76
|
+ MMGXSettingItem(QWidget* parent);
|
|
77
|
+ ~MMGXSettingItem() override = default;
|
|
78
|
+
|
|
79
|
+ void updateInfo(MMGXAxisInfo& info);
|
|
80
|
+ FT_Fixed value() { return actualValue_; }
|
|
81
|
+ void setValue(FT_Fixed value);
|
|
82
|
+ void resetDefault();
|
|
83
|
+
|
|
84
|
+signals:
|
|
85
|
+ void valueChanged();
|
|
86
|
+
|
|
87
|
+private:
|
|
88
|
+ QLabel* nameLabel_;
|
|
89
|
+ QSlider* slider_;
|
|
90
|
+ QPushButton* resetDefaultButton_;
|
|
91
|
+ QLineEdit* valueLineEdit_;
|
|
92
|
+ QDoubleValidator* valueValidator_;
|
|
93
|
+
|
|
94
|
+ QGridLayout* mainLayout_;
|
|
95
|
+
|
|
96
|
+ FT_Fixed actualValue_;
|
|
97
|
+ MMGXAxisInfo axisInfo_;
|
|
98
|
+
|
|
99
|
+ void createLayout();
|
|
100
|
+ void createConnections();
|
|
101
|
+ void sliderValueChanged();
|
|
102
|
+ void lineEditChanged();
|
|
103
|
+ void updateLineEdit();
|
|
104
|
+ void updateSlider();
|
|
105
|
+ void resetDefaultSingle();
|
|
106
|
+};
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+// end of settingpanelmmgx.hpp |
|