Commits:
-
506f3fa3
by Charlie Jiang
at 2022-07-22T14:13:51+08:00
[ftinspect] Reflect the conflict of options in the GUI.
In "Continous View", some options conflict with each other. This should be
reflected in the GUI by graying out the conflicting options.
Because the enabled state of "Vertical" checkbox involves multiple factors,
check function for mode and source are unified as `checkModeSource`.
* src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
As described.
-
976ad047
by Charlie Jiang
at 2022-07-22T14:17:32+08:00
* src/ftinspect/panels/continuous.cpp: Center the text string by default.
-
02fc3d28
by Charlie Jiang
at 2022-07-22T14:50:21+08:00
[ftinspect] Improve Waterfall mode.
* src/ftinspect/rendering/glyphcontinuous.cpp,
src/ftinspect/rendering/glyphcontinuous.hpp:
Don't paint the red square (placeholder for zero x-advance glyphs) when in
Waterfall mode.
Use the `StringRenderer`'s line begin callback to render a font point size
prefix when in Waterfall mode. `sizeIndicatorOffset_` shifts the whole
string right.
* src/ftinspect/engine/stringrenderer.cpp: Fix `pointSize` return type.
Add `isWaterfall` func.
Add support to line begin hook callback.
* src/ftinspect/engine/engine.hpp: `pointSize` func should return `double`.
7 changed files:
Changes:
src/ftinspect/engine/engine.hpp
... |
... |
@@ -108,7 +108,7 @@ public: |
108
|
108
|
FT_Library ftLibrary() const { return library_; }
|
109
|
109
|
FTC_Manager cacheManager() { return cacheManager_; }
|
110
|
110
|
int dpi() { return dpi_; }
|
111
|
|
- int pointSize() { return pointSize_; }
|
|
111
|
+ double pointSize() { return pointSize_; }
|
112
|
112
|
int currentFontType() const { return fontType_; }
|
113
|
113
|
const QString& currentFamilyName() { return curFamilyName_; }
|
114
|
114
|
const QString& currentStyleName() { return curStyleName_; }
|
src/ftinspect/engine/stringrenderer.cpp
... |
... |
@@ -350,7 +350,7 @@ StringRenderer::render(int width, |
350
|
350
|
// Waterfall
|
351
|
351
|
|
352
|
352
|
vertical_ = false;
|
353
|
|
- auto originalSize = engine_->pointSize() * 64;
|
|
353
|
+ auto originalSize = static_cast<int>(engine_->pointSize() * 64);
|
354
|
354
|
auto ptSize = originalSize;
|
355
|
355
|
auto ptHeight = 64 * 72 * height / engine_->dpi();
|
356
|
356
|
auto step = (ptSize * ptSize / ptHeight + 64) & ~63;
|
... |
... |
@@ -431,7 +431,7 @@ StringRenderer::renderLine(int x, |
431
|
431
|
{
|
432
|
432
|
if (x < 0 || y < 0 || x > width || y > height)
|
433
|
433
|
return 0;
|
434
|
|
-
|
|
434
|
+
|
435
|
435
|
y = height - y; // change to Cartesian coordinates
|
436
|
436
|
|
437
|
437
|
FT_Vector pen = { 0, 0 };
|
... |
... |
@@ -462,6 +462,11 @@ StringRenderer::renderLine(int x, |
462
|
462
|
pen.x = (x << 6) - pen.x;
|
463
|
463
|
pen.y = (y << 6) - pen.y;
|
464
|
464
|
|
|
465
|
+ // Need to transform the coord back to normal coord system
|
|
466
|
+ lineBeginCallback_({ (pen.x >> 6),
|
|
467
|
+ height - (pen.y >> 6) },
|
|
468
|
+ engine_->pointSize());
|
|
469
|
+
|
465
|
470
|
for (int i = offset; i < totalCount + offset; i++)
|
466
|
471
|
{
|
467
|
472
|
auto& ctx = activeGlyphs_[i % activeGlyphs_.size()];
|
src/ftinspect/engine/stringrenderer.hpp
... |
... |
@@ -57,7 +57,8 @@ public: |
57
|
57
|
};
|
58
|
58
|
|
59
|
59
|
using RenderCallback = std::function<void(FT_Glyph)>;
|
60
|
|
- /* The glyph pointer may be replaced. In that case, ownership is transfered
|
|
60
|
+ /*
|
|
61
|
+ * The glyph pointer may be replaced. In that case, ownership is transfered
|
61
|
62
|
* to the renderer, and the new glyph will be eventually freed by
|
62
|
63
|
* the renderer. The callback is responsible to free the old glyph.
|
63
|
64
|
* This allows you to do the following:
|
... |
... |
@@ -69,16 +70,32 @@ public: |
69
|
70
|
* }
|
70
|
71
|
*/
|
71
|
72
|
using PreprocessCallback = std::function<void(FT_Glyph*)>;
|
|
73
|
+ /*
|
|
74
|
+ * Called when a new line begins.
|
|
75
|
+ * The 1st parameter is the initial pen position;
|
|
76
|
+ * The 2nd parameter is the current size in points.
|
|
77
|
+ */
|
|
78
|
+ using LineBeginCallback = std::function<void(FT_Vector, double)>;
|
72
|
79
|
|
73
|
|
- void setCharMapIndex(int charMapIndex, int limitIndex);
|
74
|
|
- void setCallback(RenderCallback cb)
|
|
80
|
+ bool isWaterfall() { return waterfall_; }
|
|
81
|
+
|
|
82
|
+ void
|
|
83
|
+ setCallback(RenderCallback cb)
|
75
|
84
|
{
|
76
|
85
|
renderCallback_ = std::move(cb);
|
77
|
86
|
}
|
78
|
|
- void setPreprocessCallback(PreprocessCallback cb)
|
|
87
|
+ void
|
|
88
|
+ setPreprocessCallback(PreprocessCallback cb)
|
79
|
89
|
{
|
80
|
90
|
glyphPreprocessCallback_ = std::move(cb);
|
81
|
91
|
}
|
|
92
|
+ void
|
|
93
|
+ setLineBeginCallback(LineBeginCallback cb)
|
|
94
|
+ {
|
|
95
|
+ lineBeginCallback_ = std::move(cb);
|
|
96
|
+ }
|
|
97
|
+
|
|
98
|
+ void setCharMapIndex(int charMapIndex, int limitIndex);
|
82
|
99
|
void setRepeated(bool repeated) { repeated_ = repeated; }
|
83
|
100
|
void setVertical(bool vertical) { vertical_ = vertical; }
|
84
|
101
|
void setRotation(double rotation);
|
... |
... |
@@ -151,6 +168,7 @@ private: |
151
|
168
|
|
152
|
169
|
RenderCallback renderCallback_;
|
153
|
170
|
PreprocessCallback glyphPreprocessCallback_;
|
|
171
|
+ LineBeginCallback lineBeginCallback_;
|
154
|
172
|
|
155
|
173
|
void reloadGlyphIndices();
|
156
|
174
|
void prepareRendering();
|
src/ftinspect/panels/continuous.cpp
... |
... |
@@ -17,8 +17,7 @@ ContinuousTab::ContinuousTab(QWidget* parent, |
17
|
17
|
std::vector<CharMapInfo> tempCharMaps;
|
18
|
18
|
setCharMaps(tempCharMaps); // pass in an empty one
|
19
|
19
|
|
20
|
|
- checkMode();
|
21
|
|
- checkSource();
|
|
20
|
+ checkModeSource();
|
22
|
21
|
setDefaults();
|
23
|
22
|
|
24
|
23
|
createConnections();
|
... |
... |
@@ -174,7 +173,7 @@ ContinuousTab::updateLimitIndex() |
174
|
173
|
|
175
|
174
|
|
176
|
175
|
void
|
177
|
|
-ContinuousTab::checkMode()
|
|
176
|
+ContinuousTab::checkModeSource()
|
178
|
177
|
{
|
179
|
178
|
auto isFancy = modeSelector_->currentIndex() == GlyphContinuous::M_Fancy;
|
180
|
179
|
auto isStroked = modeSelector_->currentIndex() == GlyphContinuous::M_Stroked;
|
... |
... |
@@ -183,23 +182,32 @@ ContinuousTab::checkMode() |
183
|
182
|
slantSpinBox_->setEnabled(isFancy);
|
184
|
183
|
strokeRadiusSpinBox_->setEnabled(isStroked);
|
185
|
184
|
|
186
|
|
- repaintGlyph();
|
187
|
|
-}
|
188
|
|
-
|
189
|
|
-
|
190
|
|
-void
|
191
|
|
-ContinuousTab::checkSource()
|
192
|
|
-{
|
193
|
185
|
auto src
|
194
|
186
|
= static_cast<GlyphContinuous::Source>(sourceSelector_->currentIndex());
|
|
187
|
+ auto isTextStrict = src == GlyphContinuous::SRC_TextString;
|
195
|
188
|
auto isText = src == GlyphContinuous::SRC_TextString
|
196
|
189
|
|| src == GlyphContinuous::SRC_TextStringRepeated;
|
197
|
190
|
indexSelector_->setEnabled(src == GlyphContinuous::SRC_AllGlyphs);
|
198
|
191
|
sourceTextEdit_->setEnabled(isText);
|
199
|
|
- verticalCheckBox_->setEnabled(isText);
|
200
|
192
|
positionSlider_->setEnabled(isText);
|
201
|
193
|
canvas_->setSource(src);
|
202
|
194
|
|
|
195
|
+ {
|
|
196
|
+ auto wf = waterfallCheckBox_->isChecked();
|
|
197
|
+ QSignalBlocker blocker(verticalCheckBox_);
|
|
198
|
+ if (wf || !isTextStrict)
|
|
199
|
+ verticalCheckBox_->setChecked(false);
|
|
200
|
+ verticalCheckBox_->setEnabled(!wf && isTextStrict);
|
|
201
|
+ }
|
|
202
|
+
|
|
203
|
+ {
|
|
204
|
+ auto vert = verticalCheckBox_->isChecked();
|
|
205
|
+ QSignalBlocker blocker(waterfallCheckBox_);
|
|
206
|
+ if (vert)
|
|
207
|
+ waterfallCheckBox_->setChecked(false);
|
|
208
|
+ waterfallCheckBox_->setEnabled(!vert);
|
|
209
|
+ }
|
|
210
|
+
|
203
|
211
|
repaintGlyph();
|
204
|
212
|
}
|
205
|
213
|
|
... |
... |
@@ -390,11 +398,11 @@ ContinuousTab::createConnections() |
390
|
398
|
connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
|
391
|
399
|
this, &ContinuousTab::repaintGlyph);
|
392
|
400
|
connect(modeSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
393
|
|
- this, &ContinuousTab::checkMode);
|
|
401
|
+ this, &ContinuousTab::checkModeSource);
|
394
|
402
|
connect(charMapSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
395
|
403
|
this, &ContinuousTab::charMapChanged);
|
396
|
404
|
connect(sourceSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
397
|
|
- this, &ContinuousTab::checkSource);
|
|
405
|
+ this, &ContinuousTab::checkModeSource);
|
398
|
406
|
|
399
|
407
|
connect(xEmboldeningSpinBox_,
|
400
|
408
|
QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
... |
... |
@@ -413,9 +421,9 @@ ContinuousTab::createConnections() |
413
|
421
|
this, &ContinuousTab::repaintGlyph);
|
414
|
422
|
|
415
|
423
|
connect(waterfallCheckBox_, &QCheckBox::clicked,
|
416
|
|
- this, &ContinuousTab::repaintGlyph);
|
|
424
|
+ this, &ContinuousTab::checkModeSource);
|
417
|
425
|
connect(verticalCheckBox_, &QCheckBox::clicked,
|
418
|
|
- this, &ContinuousTab::repaintGlyph);
|
|
426
|
+ this, &ContinuousTab::checkModeSource);
|
419
|
427
|
connect(kerningCheckBox_, &QCheckBox::clicked,
|
420
|
428
|
this, &ContinuousTab::reloadGlyphsAndRepaint);
|
421
|
429
|
connect(sourceTextEdit_, &QPlainTextEdit::textChanged,
|
... |
... |
@@ -435,6 +443,8 @@ ContinuousTab::setDefaults() |
435
|
443
|
strokeRadiusSpinBox_->setValue(0.02);
|
436
|
444
|
rotationSpinBox_->setValue(0);
|
437
|
445
|
|
|
446
|
+ positionSlider_->setValue(50);
|
|
447
|
+
|
438
|
448
|
canvas_->setSourceText(sourceTextEdit_->toPlainText());
|
439
|
449
|
canvas_->setSource(GlyphContinuous::SRC_AllGlyphs);
|
440
|
450
|
}
|
src/ftinspect/panels/continuous.hpp
... |
... |
@@ -44,8 +44,7 @@ public: |
44
|
44
|
void setCharMaps(std::vector<CharMapInfo>& charMaps);
|
45
|
45
|
// This doesn't trigger either.
|
46
|
46
|
void updateLimitIndex();
|
47
|
|
- void checkMode();
|
48
|
|
- void checkSource();
|
|
47
|
+ void checkModeSource();
|
49
|
48
|
void charMapChanged();
|
50
|
49
|
void sourceTextChanged();
|
51
|
50
|
void reloadGlyphsAndRepaint();
|
src/ftinspect/rendering/glyphcontinuous.cpp
... |
... |
@@ -106,6 +106,11 @@ GlyphContinuous::paintByRenderer(QPainter* painter) |
106
|
106
|
{
|
107
|
107
|
preprocessGlyph(ptr);
|
108
|
108
|
});
|
|
109
|
+ stringRenderer_.setLineBeginCallback(
|
|
110
|
+ [&](FT_Vector pos, double size)
|
|
111
|
+ {
|
|
112
|
+ beginLine(painter, pos, size);
|
|
113
|
+ });
|
109
|
114
|
displayingCount_ = stringRenderer_.render(width(), height(), beginIndex_);
|
110
|
115
|
}
|
111
|
116
|
|
... |
... |
@@ -229,6 +234,31 @@ GlyphContinuous::preprocessGlyph(FT_Glyph* glyphPtr) |
229
|
234
|
}
|
230
|
235
|
|
231
|
236
|
|
|
237
|
+void
|
|
238
|
+GlyphContinuous::beginLine(QPainter* painter,
|
|
239
|
+ FT_Vector pos,
|
|
240
|
+ double sizePoint)
|
|
241
|
+{
|
|
242
|
+ // Now only used by waterfall mode to draw a size indicator.
|
|
243
|
+ if (!stringRenderer_.isWaterfall())
|
|
244
|
+ {
|
|
245
|
+ sizeIndicatorOffset_ = 0;
|
|
246
|
+ return;
|
|
247
|
+ }
|
|
248
|
+
|
|
249
|
+ auto oldFont = painter->font();
|
|
250
|
+ oldFont.setPointSizeF(sizePoint);
|
|
251
|
+ painter->setFont(oldFont);
|
|
252
|
+ auto metrics = painter->fontMetrics();
|
|
253
|
+
|
|
254
|
+ auto sizePrefix = QString("%1: ").arg(sizePoint);
|
|
255
|
+ QPoint posQ = { pos.x, pos.y };
|
|
256
|
+ painter->drawText(posQ, sizePrefix);
|
|
257
|
+
|
|
258
|
+ sizeIndicatorOffset_ = metrics.horizontalAdvance(sizePrefix);
|
|
259
|
+}
|
|
260
|
+
|
|
261
|
+
|
232
|
262
|
void
|
233
|
263
|
GlyphContinuous::drawSingleGlyph(QPainter* painter, FT_Glyph glyph)
|
234
|
264
|
{
|
... |
... |
@@ -236,7 +266,7 @@ GlyphContinuous::drawSingleGlyph(QPainter* painter, FT_Glyph glyph) |
236
|
266
|
int width = glyph->advance.x ? glyph->advance.x >> 16
|
237
|
267
|
: metrics_.y_ppem / 2;
|
238
|
268
|
|
239
|
|
- if (glyph->advance.x == 0)
|
|
269
|
+ if (glyph->advance.x == 0 && !stringRenderer_.isWaterfall())
|
240
|
270
|
{
|
241
|
271
|
// Draw a red square to indicate
|
242
|
272
|
painter->fillRect(x_, y_ - width, width, width,
|
... |
... |
@@ -245,7 +275,8 @@ GlyphContinuous::drawSingleGlyph(QPainter* painter, FT_Glyph glyph) |
245
|
275
|
|
246
|
276
|
QRect rect;
|
247
|
277
|
QImage* image = engine_->convertGlyphToQImage(glyph, &rect, false);
|
248
|
|
- rect.setTop(height() - rect.top());
|
|
278
|
+ rect.setTop(height() - rect.top()); // TODO Don't place this here...
|
|
279
|
+ rect.setLeft(rect.left() + sizeIndicatorOffset_);
|
249
|
280
|
|
250
|
281
|
painter->drawImage(rect.topLeft(), *image);
|
251
|
282
|
delete image;
|
src/ftinspect/rendering/glyphcontinuous.hpp
... |
... |
@@ -75,6 +75,7 @@ private: |
75
|
75
|
double boldX_, boldY_, slant_;
|
76
|
76
|
double strokeRadius_;
|
77
|
77
|
QString text_;
|
|
78
|
+ int sizeIndicatorOffset_; // For Waterfall Rendering...
|
78
|
79
|
|
79
|
80
|
int displayingCount_ = 0;
|
80
|
81
|
FT_Size_Metrics metrics_;
|
... |
... |
@@ -96,6 +97,9 @@ private: |
96
|
97
|
void prePaint();
|
97
|
98
|
void updateRendererText();
|
98
|
99
|
void preprocessGlyph(FT_Glyph* glyphPtr);
|
|
100
|
+ void beginLine(QPainter* painter,
|
|
101
|
+ FT_Vector pos,
|
|
102
|
+ double sizePoint);
|
99
|
103
|
void drawSingleGlyph(QPainter* painter,
|
100
|
104
|
FT_Glyph glyph);
|
101
|
105
|
};
|
|