Commits:
-
e458f62c
by Charlie Jiang
at 2022-08-02T00:01:18+08:00
[ftinspect] WIP: Add "Glyph Details" dock panel.
Open a "Glyph Details" tool panel when a glyph in the Continuous View is
clicked, showing info and enlarged view of the glyph.
TODO: Add more info lines.
* src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
Add the ctor arguments and fields to hold the dock panel and glyph details
widget. Add `updateGlyphDetails` func to handle events to open the panel.
* src/ftinspect/rendering/glyphbitmap.cpp,
src/ftinspect/rendering/glyphbitmap.hpp: Add `GlyphBitmapWidget` class to
render a `GlyphBitmap` without `QGraphicsView`. Add a new ctor passing in
`QImage` to the `GlyphBitmap`.
* src/ftinspect/panels/glyphdetails.cpp,
src/ftinspect/panels/glyphdetails.hpp: New files.
* src/ftinspect/rendering/glyphcontinuous.cpp,
src/ftinspect/rendering/glyphcontinuous.hpp: Support opening glyph details
window. Make the related change since `StringRenderer` no longer translate
the glyph to the pen position.
* src/ftinspect/maingui.cpp: Add `GlyphDetails` and the corresponding
`QDockWidget`, and pass them to the continuous view.
* src/ftinspect/uihelper.cpp, src/ftinspect/uihelper.hpp: Add
`setLabelSelectable` function.
* src/ftinspect/engine/stringrenderer.cpp:
Fix `setX/Y` bug. Fix crash about `prev` pointer when `resize` is called
(which invalidates the `prev` pointer)
Don't translate the glyph to the target point, but let the draw routine
to draw it at the correct pen position.
* src/ftinspect/engine/engine.cpp: Fix bug: use `moveLeft/Top` instead of
`setX/Y`. Honestly I don't know why it works before...
* src/ftinspect/engine/stringrenderer.hpp: Add `charMapIndex` getter.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
-
e11ed2d6
by Charlie Jiang
at 2022-08-02T23:22:07+08:00
[ftinspect] Add more info entries to the glyph details panel.
Now it shows metrics, ink info and bitmap offset. Also fix a bug in
`StringRenderer` so translating to pen position of pre-rendered `QImage` is
also handled by the receiver instead of the `StringRenderer`.
* src/ftinspect/panels/glyphdetails.cpp,
src/ftinspect/panels/glyphdetails.hpp: Add entries as described.
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Add `noScale` argument to `loadGlyphIntoSlotWithoutCache` func to retrieve
metrics in font native units.
Add `inverseRectY` argument to `tryDirectRenderColorLayers`.
* src/ftinspect/engine/stringrenderer.cpp,
src/ftinspect/engine/stringrenderer.hpp:
Fix the issue that pre-rendered `QImage` is tranlated by the renderer.
Add a new argument to the `RenderImageCallback` to pass pen position.
* src/ftinspect/rendering/glyphcontinuous.cpp,
src/ftinspect/rendering/glyphcontinuous.hpp:
Handle pen position in the callback. Set `penPos` for pre-rendered image
cache entries.
* src/ftinspect/rendering/glyphbitmap.cpp,
src/ftinspect/rendering/glyphbitmap.hpp: Leverage the `inverseRectY` arg.
18 changed files:
Changes:
src/ftinspect/CMakeLists.txt
... |
... |
@@ -45,6 +45,7 @@ add_executable(ftinspect |
45
|
45
|
"panels/settingpanel.cpp"
|
46
|
46
|
"panels/singular.cpp"
|
47
|
47
|
"panels/continuous.cpp"
|
|
48
|
+ "panels/glyphdetails.cpp"
|
48
|
49
|
)
|
49
|
50
|
target_link_libraries(ftinspect
|
50
|
51
|
Qt5::Core Qt5::Widgets
|
src/ftinspect/engine/engine.cpp
... |
... |
@@ -540,9 +540,13 @@ Engine::loadGlyph(int glyphIndex) |
540
|
540
|
|
541
|
541
|
|
542
|
542
|
int
|
543
|
|
-Engine::loadGlyphIntoSlotWithoutCache(int glyphIndex)
|
|
543
|
+Engine::loadGlyphIntoSlotWithoutCache(int glyphIndex,
|
|
544
|
+ bool noScale)
|
544
|
545
|
{
|
545
|
|
- return FT_Load_Glyph(ftSize_->face, glyphIndex, loadFlags_);
|
|
546
|
+ auto flags = static_cast<int>(loadFlags_);
|
|
547
|
+ if (noScale)
|
|
548
|
+ flags |= FT_LOAD_NO_SCALE;
|
|
549
|
+ return FT_Load_Glyph(ftSize_->face, glyphIndex, flags);
|
546
|
550
|
}
|
547
|
551
|
|
548
|
552
|
|
... |
... |
@@ -1019,7 +1023,8 @@ Engine::computeGlyphOffset(FT_Glyph glyph, bool inverseY) |
1019
|
1023
|
|
1020
|
1024
|
QImage*
|
1021
|
1025
|
Engine::tryDirectRenderColorLayers(int glyphIndex,
|
1022
|
|
- QRect* outRect)
|
|
1026
|
+ QRect* outRect,
|
|
1027
|
+ bool inverseRectY)
|
1023
|
1028
|
{
|
1024
|
1029
|
if (palette_ == NULL
|
1025
|
1030
|
|| !useColorLayer_
|
... |
... |
@@ -1131,9 +1136,12 @@ Engine::tryDirectRenderColorLayers(int glyphIndex, |
1131
|
1136
|
auto img = convertBitmapToQImage(&bitmap);
|
1132
|
1137
|
if (outRect)
|
1133
|
1138
|
{
|
|
1139
|
+ outRect->moveLeft(bitmapOffset.x >> 6);
|
|
1140
|
+ if (inverseRectY)
|
|
1141
|
+ outRect->moveTop(-bitmapOffset.y >> 6);
|
|
1142
|
+ else
|
|
1143
|
+ outRect->moveTop(bitmapOffset.y >> 6);
|
1134
|
1144
|
outRect->setSize(img->size());
|
1135
|
|
- outRect->setLeft(bitmapOffset.x >> 6);
|
1136
|
|
- outRect->setTop(bitmapOffset.y >> 6);
|
1137
|
1145
|
}
|
1138
|
1146
|
|
1139
|
1147
|
FT_Bitmap_Done(library_, &bitmap);
|
src/ftinspect/engine/engine.hpp
... |
... |
@@ -79,7 +79,7 @@ public: |
79
|
79
|
long faceIndex,
|
80
|
80
|
int namedInstanceIndex); // return number of glyphs
|
81
|
81
|
FT_Glyph loadGlyph(int glyphIndex);
|
82
|
|
- int loadGlyphIntoSlotWithoutCache(int glyphIndex);
|
|
82
|
+ int loadGlyphIntoSlotWithoutCache(int glyphIndex, bool noScale = false);
|
83
|
83
|
|
84
|
84
|
// Sometimes the engine is already updated, and we want to be faster
|
85
|
85
|
FT_Glyph loadGlyphWithoutUpdate(int glyphIndex,
|
... |
... |
@@ -106,7 +106,8 @@ public: |
106
|
106
|
* Will return NULL if not enabled or color layers not available.
|
107
|
107
|
*/
|
108
|
108
|
QImage* tryDirectRenderColorLayers(int glyphIndex,
|
109
|
|
- QRect* outRect);
|
|
109
|
+ QRect* outRect,
|
|
110
|
+ bool inverseRectY = false);
|
110
|
111
|
|
111
|
112
|
// reload current triplet, but with updated settings, useful for updating
|
112
|
113
|
// `ftSize_` only
|
src/ftinspect/engine/stringrenderer.cpp
... |
... |
@@ -269,7 +269,6 @@ StringRenderer::prepareLine(int offset, |
269
|
269
|
// TODO: Optimize: use a sparse vector...!
|
270
|
270
|
// The problem is that when doing a `list::resize`, the ctor is called
|
271
|
271
|
// for unnecessarily many times.
|
272
|
|
- GlyphContext* prev = &tempGlyphContext_;
|
273
|
272
|
tempGlyphContext_ = {};
|
274
|
273
|
for (unsigned n = offset; n < static_cast<unsigned>(limitIndex_);)
|
275
|
274
|
{
|
... |
... |
@@ -283,6 +282,7 @@ StringRenderer::prepareLine(int offset, |
283
|
282
|
ctx.glyphIndex = static_cast<int>(
|
284
|
283
|
engine_->glyphIndexFromCharCode(static_cast<int>(n), charMapIndex_));
|
285
|
284
|
|
|
285
|
+ auto prev = n == 0 ? &tempGlyphContext_ : &activeGlyphs_[n - 1];
|
286
|
286
|
if (!ctx.glyph)
|
287
|
287
|
loadSingleContext(&ctx, prev);
|
288
|
288
|
|
... |
... |
@@ -292,7 +292,6 @@ StringRenderer::prepareLine(int offset, |
292
|
292
|
outActualLineWidth.y += ctx.hadvance.y;
|
293
|
293
|
++n;
|
294
|
294
|
++totalCount;
|
295
|
|
- prev = &ctx;
|
296
|
295
|
}
|
297
|
296
|
}
|
298
|
297
|
else
|
... |
... |
@@ -504,13 +503,12 @@ StringRenderer::renderLine(int x, |
504
|
503
|
|
505
|
504
|
QRect rect;
|
506
|
505
|
QImage* colorLayerImage
|
507
|
|
- = engine_->tryDirectRenderColorLayers(ctx.glyphIndex, &rect);
|
|
506
|
+ = engine_->tryDirectRenderColorLayers(ctx.glyphIndex, &rect, true);
|
508
|
507
|
|
509
|
508
|
if (colorLayerImage)
|
510
|
509
|
{
|
511
|
|
- rect.setX(rect.x() + (pen.x >> 6));
|
512
|
|
- rect.setY(height - rect.y() - (pen.y >> 6));
|
513
|
|
- renderImageCallback_(colorLayerImage, rect, advance, ctx);
|
|
510
|
+ FT_Vector penPos = { (pen.x >> 6), height - (pen.y >> 6) };
|
|
511
|
+ renderImageCallback_(colorLayerImage, rect, penPos, advance, ctx);
|
514
|
512
|
}
|
515
|
513
|
else
|
516
|
514
|
{
|
... |
... |
@@ -529,9 +527,7 @@ StringRenderer::renderLine(int x, |
529
|
527
|
if (!error)
|
530
|
528
|
{
|
531
|
529
|
if (matrixEnabled_)
|
532
|
|
- error = FT_Glyph_Transform(image, &matrix_, &pen);
|
533
|
|
- else
|
534
|
|
- error = FT_Glyph_Transform(image, NULL, &pen);
|
|
530
|
+ error = FT_Glyph_Transform(image, &matrix_, NULL);
|
535
|
531
|
}
|
536
|
532
|
|
537
|
533
|
if (error)
|
... |
... |
@@ -544,15 +540,10 @@ StringRenderer::renderLine(int x, |
544
|
540
|
{
|
545
|
541
|
auto bitmap = reinterpret_cast<FT_BitmapGlyph>(image);
|
546
|
542
|
|
547
|
|
- if (vertical_)
|
548
|
|
- {
|
549
|
|
- bitmap->left += (ctx.vvector.x + pen.x) >> 6;
|
550
|
|
- bitmap->top += (ctx.vvector.y + pen.y) >> 6;
|
551
|
|
- }
|
552
|
|
- else
|
|
543
|
+ if (vertical_)
|
553
|
544
|
{
|
554
|
|
- bitmap->left += pen.x >> 6;
|
555
|
|
- bitmap->top += pen.y >> 6;
|
|
545
|
+ bitmap->left += (ctx.vvector.x) >> 6;
|
|
546
|
+ bitmap->top += (ctx.vvector.y) >> 6;
|
556
|
547
|
}
|
557
|
548
|
}
|
558
|
549
|
|
src/ftinspect/engine/stringrenderer.hpp
... |
... |
@@ -70,8 +70,9 @@ public: |
70
|
70
|
* The receiver is responsible for deleteing the QImage.
|
71
|
71
|
*/
|
72
|
72
|
using RenderImageCallback = std::function<void(QImage*,
|
73
|
|
- QRect,
|
74
|
|
- FT_Vector,
|
|
73
|
+ QRect,
|
|
74
|
+ FT_Vector, // penPos
|
|
75
|
+ FT_Vector, // advance
|
75
|
76
|
GlyphContext&)>;
|
76
|
77
|
/*
|
77
|
78
|
* The glyph pointer may be replaced. In that case, ownership is transfered
|
... |
... |
@@ -95,6 +96,7 @@ public: |
95
|
96
|
|
96
|
97
|
bool isWaterfall() { return waterfall_; }
|
97
|
98
|
double position(){ return position_; }
|
|
99
|
+ int charMapIndex() { return charMapIndex_; }
|
98
|
100
|
|
99
|
101
|
void
|
100
|
102
|
setCallback(RenderCallback cb)
|
src/ftinspect/maingui.cpp
... |
... |
@@ -191,6 +191,13 @@ MainGUI::syncSettings() |
191
|
191
|
void
|
192
|
192
|
MainGUI::createLayout()
|
193
|
193
|
{
|
|
194
|
+ // floating
|
|
195
|
+ glyphDetails_ = new GlyphDetails(this, engine_);
|
|
196
|
+ glyphDetailsDockWidget_ = new QDockWidget(tr("Glyph Details"), this);
|
|
197
|
+ glyphDetailsDockWidget_->setWidget(glyphDetails_);
|
|
198
|
+ glyphDetailsDockWidget_->setFloating(true);
|
|
199
|
+ glyphDetailsDockWidget_->hide();
|
|
200
|
+
|
194
|
201
|
// left side
|
195
|
202
|
settingPanel_ = new SettingPanel(this, engine_);
|
196
|
203
|
|
... |
... |
@@ -212,7 +219,8 @@ MainGUI::createLayout() |
212
|
219
|
|
213
|
220
|
// right side
|
214
|
221
|
singularTab_ = new SingularTab(this, engine_);
|
215
|
|
- continuousTab_ = new ContinuousTab(this, engine_);
|
|
222
|
+ continuousTab_ = new ContinuousTab(this, engine_,
|
|
223
|
+ glyphDetailsDockWidget_, glyphDetails_);
|
216
|
224
|
|
217
|
225
|
tabWidget_ = new QTabWidget(this);
|
218
|
226
|
|
src/ftinspect/maingui.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
#include "panels/settingpanel.hpp"
|
11
|
11
|
#include "panels/singular.hpp"
|
12
|
12
|
#include "panels/continuous.hpp"
|
|
13
|
+#include "panels/glyphdetails.hpp"
|
13
|
14
|
|
14
|
15
|
#include <QAction>
|
15
|
16
|
#include <QCheckBox>
|
... |
... |
@@ -19,6 +20,7 @@ |
19
|
20
|
#include <QFileSystemWatcher>
|
20
|
21
|
#include <QGridLayout>
|
21
|
22
|
#include <QHash>
|
|
23
|
+#include <QDockWidget>
|
22
|
24
|
#include <QHBoxLayout>
|
23
|
25
|
#include <QLabel>
|
24
|
26
|
#include <QList>
|
... |
... |
@@ -108,6 +110,9 @@ private: |
108
|
110
|
SingularTab* singularTab_;
|
109
|
111
|
ContinuousTab* continuousTab_;
|
110
|
112
|
|
|
113
|
+ QDockWidget* glyphDetailsDockWidget_;
|
|
114
|
+ GlyphDetails* glyphDetails_;
|
|
115
|
+
|
111
|
116
|
void openFonts(QStringList const& fileNames);
|
112
|
117
|
|
113
|
118
|
void syncSettings();
|
src/ftinspect/meson.build
... |
... |
@@ -45,6 +45,7 @@ if qt5_dep.found() |
45
|
45
|
'panels/settingpanel.cpp',
|
46
|
46
|
'panels/singular.cpp',
|
47
|
47
|
'panels/continuous.cpp',
|
|
48
|
+ 'panels/glyphdetails.cpp',
|
48
|
49
|
|
49
|
50
|
'ftinspect.cpp',
|
50
|
51
|
'maingui.cpp',
|
... |
... |
@@ -63,6 +64,7 @@ if qt5_dep.found() |
63
|
64
|
'panels/settingpanel.hpp',
|
64
|
65
|
'panels/singular.hpp',
|
65
|
66
|
'panels/continuous.hpp',
|
|
67
|
+ 'panels/glyphdetails.hpp',
|
66
|
68
|
'maingui.hpp',
|
67
|
69
|
],
|
68
|
70
|
dependencies: qt5_dep)
|
src/ftinspect/panels/continuous.cpp
... |
... |
@@ -4,13 +4,20 @@ |
4
|
4
|
|
5
|
5
|
#include "continuous.hpp"
|
6
|
6
|
|
|
7
|
+#include "glyphdetails.hpp"
|
|
8
|
+
|
7
|
9
|
#include <climits>
|
8
|
10
|
#include <QVariant>
|
9
|
11
|
|
10
|
12
|
|
11
|
13
|
ContinuousTab::ContinuousTab(QWidget* parent,
|
12
|
|
- Engine* engine)
|
13
|
|
-: QWidget(parent), engine_(engine)
|
|
14
|
+ Engine* engine,
|
|
15
|
+ QDockWidget* gdWidget,
|
|
16
|
+ GlyphDetails* glyphDetails)
|
|
17
|
+: QWidget(parent),
|
|
18
|
+ engine_(engine),
|
|
19
|
+ glyphDetailsWidget_(gdWidget),
|
|
20
|
+ glyphDetails_(glyphDetails)
|
14
|
21
|
{
|
15
|
22
|
createLayout();
|
16
|
23
|
|
... |
... |
@@ -260,6 +267,17 @@ ContinuousTab::changeBeginIndexFromCanvas(int index) |
260
|
267
|
}
|
261
|
268
|
|
262
|
269
|
|
|
270
|
+void
|
|
271
|
+ContinuousTab::updateGlyphDetails(GlyphCacheEntry* ctxt,
|
|
272
|
+ int charMapIndex,
|
|
273
|
+ bool open)
|
|
274
|
+{
|
|
275
|
+ glyphDetails_->updateGlyph(*ctxt, charMapIndex);
|
|
276
|
+ if (open)
|
|
277
|
+ glyphDetailsWidget_->setVisible(true);
|
|
278
|
+}
|
|
279
|
+
|
|
280
|
+
|
263
|
281
|
bool
|
264
|
282
|
ContinuousTab::eventFilter(QObject* watched,
|
265
|
283
|
QEvent* event)
|
... |
... |
@@ -413,6 +431,8 @@ ContinuousTab::createConnections() |
413
|
431
|
this, &ContinuousTab::switchToSingular);
|
414
|
432
|
connect(canvas_, &GlyphContinuous::beginIndexChangeRequest,
|
415
|
433
|
this, &ContinuousTab::changeBeginIndexFromCanvas);
|
|
434
|
+ connect(canvas_, &GlyphContinuous::updateGlyphDetails,
|
|
435
|
+ this, &ContinuousTab::updateGlyphDetails);
|
416
|
436
|
|
417
|
437
|
connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
|
418
|
438
|
this, &ContinuousTab::repaintGlyph);
|
src/ftinspect/panels/continuous.hpp
... |
... |
@@ -19,14 +19,17 @@ |
19
|
19
|
#include <QGridLayout>
|
20
|
20
|
#include <QBoxLayout>
|
21
|
21
|
#include <QPlainTextEdit>
|
|
22
|
+#include <QDockWidget>
|
22
|
23
|
#include <QCheckBox>
|
23
|
24
|
|
|
25
|
+class GlyphDetails;
|
24
|
26
|
class ContinuousTab
|
25
|
27
|
: public QWidget, public AbstractTab
|
26
|
28
|
{
|
27
|
29
|
Q_OBJECT
|
28
|
30
|
public:
|
29
|
|
- ContinuousTab(QWidget* parent, Engine* engine);
|
|
31
|
+ ContinuousTab(QWidget* parent, Engine* engine,
|
|
32
|
+ QDockWidget* gdWidget, GlyphDetails* glyphDetails);
|
30
|
33
|
~ContinuousTab() override = default;
|
31
|
34
|
|
32
|
35
|
void repaintGlyph() override;
|
... |
... |
@@ -49,6 +52,9 @@ public: |
49
|
52
|
void sourceTextChanged();
|
50
|
53
|
void reloadGlyphsAndRepaint();
|
51
|
54
|
void changeBeginIndexFromCanvas(int index);
|
|
55
|
+ void updateGlyphDetails(GlyphCacheEntry* ctxt,
|
|
56
|
+ int charMapIndex,
|
|
57
|
+ bool open);
|
52
|
58
|
|
53
|
59
|
signals:
|
54
|
60
|
void switchToSingular(int glyphIndex, double sizePoint);
|
... |
... |
@@ -103,6 +109,9 @@ private: |
103
|
109
|
QGridLayout* bottomLayout_;
|
104
|
110
|
QVBoxLayout* mainLayout_;
|
105
|
111
|
|
|
112
|
+ QDockWidget* glyphDetailsWidget_;
|
|
113
|
+ GlyphDetails* glyphDetails_;
|
|
114
|
+
|
106
|
115
|
void createLayout();
|
107
|
116
|
void createConnections();
|
108
|
117
|
|
src/ftinspect/panels/glyphdetails.cpp
|
1
|
+// glyphdetails.cpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#include "glyphdetails.hpp"
|
|
6
|
+
|
|
7
|
+#include "../engine/stringrenderer.hpp"
|
|
8
|
+#include "../rendering/glyphcontinuous.hpp"
|
|
9
|
+#include "../uihelper.hpp"
|
|
10
|
+#include "../engine/engine.hpp"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+GlyphDetails::GlyphDetails(QWidget* parent,
|
|
14
|
+ Engine* engine)
|
|
15
|
+: QWidget(parent),
|
|
16
|
+ engine_(engine)
|
|
17
|
+{
|
|
18
|
+ createLayout();
|
|
19
|
+ createConnections();
|
|
20
|
+}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+GlyphDetails::~GlyphDetails()
|
|
24
|
+{
|
|
25
|
+}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+void
|
|
29
|
+GlyphDetails::updateGlyph(GlyphCacheEntry& ctxt, int charMapIndex)
|
|
30
|
+{
|
|
31
|
+ auto& cmaps = engine_->currentFontCharMaps();
|
|
32
|
+
|
|
33
|
+ glyphIndexLabel_->setText(QString::number(ctxt.glyphIndex));
|
|
34
|
+ if (charMapIndex < 0 || charMapIndex >= static_cast<int>(cmaps.size()))
|
|
35
|
+ {
|
|
36
|
+ charCodePromptLabel_->setVisible(false);
|
|
37
|
+ charCodeLabel_->setVisible(false);
|
|
38
|
+ }
|
|
39
|
+ else
|
|
40
|
+ {
|
|
41
|
+ charCodePromptLabel_->setVisible(true);
|
|
42
|
+ charCodeLabel_->setVisible(true);
|
|
43
|
+ charCodeLabel_->setText(
|
|
44
|
+ cmaps[charMapIndex].stringifyIndexShort(ctxt.charCode));
|
|
45
|
+ }
|
|
46
|
+
|
|
47
|
+ auto glyphName = engine_->glyphName(ctxt.glyphIndex);
|
|
48
|
+ if (glyphName.isEmpty())
|
|
49
|
+ glyphName = "(none)";
|
|
50
|
+ glyphNameLabel_->setText(glyphName);
|
|
51
|
+
|
|
52
|
+ auto rect = ctxt.basePosition.translated(-(ctxt.penPos.x()),
|
|
53
|
+ -(ctxt.penPos.y()));
|
|
54
|
+ bitmapWidget_->updateImage(ctxt.image, rect);
|
|
55
|
+
|
|
56
|
+ // load glyphs in all units
|
|
57
|
+ dpi_ = engine_->dpi();
|
|
58
|
+ engine_->reloadFont();
|
|
59
|
+
|
|
60
|
+ engine_->loadGlyphIntoSlotWithoutCache(ctxt.glyphIndex, true);
|
|
61
|
+ fontUnitMetrics_ = engine_->currentFaceSlot()->metrics;
|
|
62
|
+ engine_->loadGlyphIntoSlotWithoutCache(ctxt.glyphIndex, false);
|
|
63
|
+ pixelMetrics_ = engine_->currentFaceSlot()->metrics;
|
|
64
|
+
|
|
65
|
+ changeUnit(unitButtonGroup_->checkedId());
|
|
66
|
+
|
|
67
|
+ inkSizeLabel_->setText(QString("(%1, %2) px")
|
|
68
|
+ .arg(rect.width())
|
|
69
|
+ .arg(rect.height()));
|
|
70
|
+ bitmapOffsetLabel_->setText(QString("(%1, %2) px")
|
|
71
|
+ .arg(rect.x())
|
|
72
|
+ .arg(rect.y()));
|
|
73
|
+}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+void
|
|
77
|
+GlyphDetails::createLayout()
|
|
78
|
+{
|
|
79
|
+ unitButtonGroup_ = new QButtonGroup(this);
|
|
80
|
+ fontUnitButton_ = new QRadioButton(tr("Font Unit"), this);
|
|
81
|
+ pointButton_ = new QRadioButton(tr("Point"), this);
|
|
82
|
+ pixelButton_ = new QRadioButton(tr("Pixel"), this);
|
|
83
|
+ unitButtonGroup_->addButton(fontUnitButton_, DU_FontUnit);
|
|
84
|
+ unitButtonGroup_->addButton(pointButton_, DU_Point);
|
|
85
|
+ unitButtonGroup_->addButton(pixelButton_, DU_Pixel);
|
|
86
|
+ fontUnitButton_->setChecked(true);
|
|
87
|
+
|
|
88
|
+ glyphIndexPromptLabel_ = new QLabel(tr("Grid Index:"), this);
|
|
89
|
+ charCodePromptLabel_ = new QLabel(tr("Char Code:"), this);
|
|
90
|
+ glyphNamePromptLabel_ = new QLabel(tr("Glyph Name:"), this);
|
|
91
|
+
|
|
92
|
+ bboxSizePromptLabel_ = new QLabel(tr("Bounding Box Size:"), this);
|
|
93
|
+ horiBearingPromptLabel_ = new QLabel(tr("Hori. Bearing:"), this);
|
|
94
|
+ horiAdvancePromptLabel_ = new QLabel(tr("Hori. Advance:"), this);
|
|
95
|
+ vertBearingPromptLabel_ = new QLabel(tr("Vert. Bearing:"), this);
|
|
96
|
+ vertAdvancePromptLabel_ = new QLabel(tr("Vert. Advance:"), this);
|
|
97
|
+
|
|
98
|
+ inkSizePromptLabel_ = new QLabel(tr("Ink Size:"), this);
|
|
99
|
+ bitmapOffsetPromptLabel_ = new QLabel(tr("Bitmap Offset:"), this);
|
|
100
|
+
|
|
101
|
+ glyphIndexLabel_ = new QLabel(this);
|
|
102
|
+ charCodeLabel_ = new QLabel(this);
|
|
103
|
+ glyphNameLabel_ = new QLabel(this);
|
|
104
|
+
|
|
105
|
+ bboxSizeLabel_ = new QLabel(this);
|
|
106
|
+ horiBearingLabel_ = new QLabel(this);
|
|
107
|
+ horiAdvanceLabel_ = new QLabel(this);
|
|
108
|
+ vertBearingLabel_ = new QLabel(this);
|
|
109
|
+ vertAdvanceLabel_ = new QLabel(this);
|
|
110
|
+
|
|
111
|
+ inkSizeLabel_ = new QLabel(this);
|
|
112
|
+ bitmapOffsetLabel_ = new QLabel(this);
|
|
113
|
+
|
|
114
|
+ bitmapWidget_ = new GlyphBitmapWidget(this);
|
|
115
|
+
|
|
116
|
+ setLabelSelectable(glyphIndexLabel_);
|
|
117
|
+ setLabelSelectable(charCodeLabel_);
|
|
118
|
+ setLabelSelectable(glyphNameLabel_);
|
|
119
|
+ setLabelSelectable(bboxSizeLabel_);
|
|
120
|
+ setLabelSelectable(horiBearingLabel_);
|
|
121
|
+ setLabelSelectable(horiAdvanceLabel_);
|
|
122
|
+ setLabelSelectable(vertBearingLabel_);
|
|
123
|
+ setLabelSelectable(vertAdvanceLabel_);
|
|
124
|
+ setLabelSelectable(inkSizeLabel_);
|
|
125
|
+ setLabelSelectable(bitmapOffsetLabel_);
|
|
126
|
+
|
|
127
|
+ unitLayout_ = new QHBoxLayout;
|
|
128
|
+ unitLayout_->addWidget(fontUnitButton_);
|
|
129
|
+ unitLayout_->addWidget(pointButton_);
|
|
130
|
+ unitLayout_->addWidget(pixelButton_);
|
|
131
|
+
|
|
132
|
+ layout_ = new QGridLayout;
|
|
133
|
+ layout_->addLayout(unitLayout_, 0, 0, 1, 2);
|
|
134
|
+ layout_->addItem(new QSpacerItem(0, 18), 1, 0, 1, 2);
|
|
135
|
+
|
|
136
|
+ layout_->addWidget(glyphIndexPromptLabel_, 2, 0);
|
|
137
|
+ layout_->addWidget(charCodePromptLabel_, 3, 0);
|
|
138
|
+ layout_->addWidget(glyphNamePromptLabel_, 4, 0);
|
|
139
|
+ layout_->addItem(new QSpacerItem(0, 18), 5, 0, 1, 2);
|
|
140
|
+
|
|
141
|
+ layout_->addWidget(bboxSizePromptLabel_, 6, 0);
|
|
142
|
+ layout_->addWidget(horiBearingPromptLabel_, 7, 0);
|
|
143
|
+ layout_->addWidget(horiAdvancePromptLabel_, 8, 0);
|
|
144
|
+ layout_->addWidget(vertBearingPromptLabel_, 9, 0);
|
|
145
|
+ layout_->addWidget(vertAdvancePromptLabel_, 10, 0);
|
|
146
|
+ layout_->addItem(new QSpacerItem(0, 18), 11, 0, 1, 2);
|
|
147
|
+
|
|
148
|
+ layout_->addWidget(inkSizePromptLabel_, 12, 0);
|
|
149
|
+ layout_->addWidget(bitmapOffsetPromptLabel_, 13, 0);
|
|
150
|
+
|
|
151
|
+ layout_->addWidget(glyphIndexLabel_, 2, 1);
|
|
152
|
+ layout_->addWidget(charCodeLabel_, 3, 1);
|
|
153
|
+ layout_->addWidget(glyphNameLabel_, 4, 1);
|
|
154
|
+
|
|
155
|
+ layout_->addWidget(bboxSizeLabel_, 6, 1);
|
|
156
|
+ layout_->addWidget(horiBearingLabel_, 7, 1);
|
|
157
|
+ layout_->addWidget(horiAdvanceLabel_, 8, 1);
|
|
158
|
+ layout_->addWidget(vertBearingLabel_, 9, 1);
|
|
159
|
+ layout_->addWidget(vertAdvanceLabel_, 10, 1);
|
|
160
|
+
|
|
161
|
+ layout_->addWidget(inkSizeLabel_, 12, 1);
|
|
162
|
+ layout_->addWidget(bitmapOffsetLabel_, 13, 1);
|
|
163
|
+ layout_->addItem(new QSpacerItem(0, 18), 14, 0, 1, 2);
|
|
164
|
+
|
|
165
|
+ layout_->addWidget(bitmapWidget_, 15, 0, 1, 2);
|
|
166
|
+
|
|
167
|
+ layout_->setColumnStretch(1, 1);
|
|
168
|
+ layout_->setRowStretch(15, 1);
|
|
169
|
+
|
|
170
|
+ setLayout(layout_);
|
|
171
|
+ setContentsMargins(12, 12, 12, 12);
|
|
172
|
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
173
|
+}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+void
|
|
177
|
+GlyphDetails::createConnections()
|
|
178
|
+{
|
|
179
|
+ connect(unitButtonGroup_, &QButtonGroup::idClicked,
|
|
180
|
+ this, &GlyphDetails::changeUnit);
|
|
181
|
+}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+void
|
|
185
|
+GlyphDetails::changeUnit(int unitId)
|
|
186
|
+{
|
|
187
|
+ QString unitSuffix;
|
|
188
|
+ double bboxW = -1, bboxH = -1;
|
|
189
|
+ double horiBearingX = -1, horiBearingY = -1;
|
|
190
|
+ double horiAdvance = -1;
|
|
191
|
+ double vertBearingX = -1, vertBearingY = -1;
|
|
192
|
+ double vertAdvance = -1;
|
|
193
|
+ switch (static_cast<DisplayUnit>(unitId))
|
|
194
|
+ {
|
|
195
|
+ case DU_FontUnit:
|
|
196
|
+ unitSuffix = "";
|
|
197
|
+ bboxW = fontUnitMetrics_.width;
|
|
198
|
+ bboxH = fontUnitMetrics_.height;
|
|
199
|
+ horiBearingX = fontUnitMetrics_.horiBearingX;
|
|
200
|
+ horiBearingY = fontUnitMetrics_.horiBearingY;
|
|
201
|
+ horiAdvance = fontUnitMetrics_.horiAdvance;
|
|
202
|
+ vertBearingX = fontUnitMetrics_.vertBearingX;
|
|
203
|
+ vertBearingY = fontUnitMetrics_.vertBearingY;
|
|
204
|
+ vertAdvance = fontUnitMetrics_.vertAdvance;
|
|
205
|
+ break;
|
|
206
|
+
|
|
207
|
+ case DU_Point:
|
|
208
|
+ unitSuffix = " pt";
|
|
209
|
+ // 1.125 = 72 / 64
|
|
210
|
+ bboxW = pixelMetrics_.width * 1.125 / dpi_;
|
|
211
|
+ bboxH = pixelMetrics_.height * 1.125 / dpi_;
|
|
212
|
+ horiBearingX = pixelMetrics_.horiBearingX * 1.125 / dpi_;
|
|
213
|
+ horiBearingY = pixelMetrics_.horiBearingY * 1.125 / dpi_;
|
|
214
|
+ horiAdvance = pixelMetrics_.horiAdvance * 1.125 / dpi_;
|
|
215
|
+ vertBearingX = pixelMetrics_.vertBearingX * 1.125 / dpi_;
|
|
216
|
+ vertBearingY = pixelMetrics_.vertBearingY * 1.125 / dpi_;
|
|
217
|
+ vertAdvance = pixelMetrics_.vertAdvance * 1.125 / dpi_;
|
|
218
|
+ break;
|
|
219
|
+
|
|
220
|
+ case DU_Pixel:
|
|
221
|
+ unitSuffix = " px";
|
|
222
|
+ bboxW = pixelMetrics_.width/ 64.0;
|
|
223
|
+ bboxH = pixelMetrics_.height/ 64.0;
|
|
224
|
+ horiBearingX = pixelMetrics_.horiBearingX/ 64.0;
|
|
225
|
+ horiBearingY = pixelMetrics_.horiBearingY/ 64.0;
|
|
226
|
+ horiAdvance = pixelMetrics_.horiAdvance/ 64.0;
|
|
227
|
+ vertBearingX = pixelMetrics_.vertBearingX/ 64.0;
|
|
228
|
+ vertBearingY = pixelMetrics_.vertBearingY/ 64.0;
|
|
229
|
+ vertAdvance = pixelMetrics_.vertAdvance/ 64.0;
|
|
230
|
+ break;
|
|
231
|
+ }
|
|
232
|
+
|
|
233
|
+ auto tmpl = QString("%1") + unitSuffix;
|
|
234
|
+ auto tmplPair = QString("(%1, %2)") + unitSuffix;
|
|
235
|
+ bboxSizeLabel_->setText(tmplPair.arg(bboxW).arg(bboxH));
|
|
236
|
+ horiBearingLabel_->setText(tmplPair.arg(horiBearingX).arg(horiBearingY));
|
|
237
|
+ horiAdvanceLabel_->setText(tmpl.arg(horiAdvance));
|
|
238
|
+ vertBearingLabel_->setText(tmplPair.arg(vertBearingX).arg(vertBearingY));
|
|
239
|
+ vertAdvanceLabel_->setText(tmpl.arg(vertAdvance));
|
|
240
|
+}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+// end of glyphdetails.cpp |
src/ftinspect/panels/glyphdetails.hpp
|
1
|
+// glyphdetails.hpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#pragma once
|
|
6
|
+
|
|
7
|
+#include "../rendering/glyphbitmap.hpp"
|
|
8
|
+
|
|
9
|
+#include <QWidget>
|
|
10
|
+#include <QLabel>
|
|
11
|
+#include <QGridLayout>
|
|
12
|
+#include <QBoxLayout>
|
|
13
|
+#include <QImage>
|
|
14
|
+#include <QRadioButton>
|
|
15
|
+#include <QButtonGroup>
|
|
16
|
+
|
|
17
|
+#include <freetype/freetype.h>
|
|
18
|
+
|
|
19
|
+struct GlyphCacheEntry;
|
|
20
|
+class Engine;
|
|
21
|
+class GlyphDetails
|
|
22
|
+: public QWidget
|
|
23
|
+{
|
|
24
|
+public:
|
|
25
|
+ GlyphDetails(QWidget* parent, Engine* engine);
|
|
26
|
+ ~GlyphDetails() override;
|
|
27
|
+
|
|
28
|
+ void updateGlyph(GlyphCacheEntry& ctxt,
|
|
29
|
+ int charMapIndex);
|
|
30
|
+
|
|
31
|
+private:
|
|
32
|
+ Engine* engine_ = NULL;
|
|
33
|
+
|
|
34
|
+ enum DisplayUnit : int
|
|
35
|
+ {
|
|
36
|
+ DU_FontUnit,
|
|
37
|
+ DU_Point,
|
|
38
|
+ DU_Pixel
|
|
39
|
+ };
|
|
40
|
+
|
|
41
|
+ QButtonGroup* unitButtonGroup_;
|
|
42
|
+ QRadioButton* fontUnitButton_;
|
|
43
|
+ QRadioButton* pointButton_;
|
|
44
|
+ QRadioButton* pixelButton_;
|
|
45
|
+
|
|
46
|
+ QLabel* glyphIndexPromptLabel_;
|
|
47
|
+ QLabel* charCodePromptLabel_;
|
|
48
|
+ QLabel* glyphNamePromptLabel_;
|
|
49
|
+ QLabel* bboxSizePromptLabel_;
|
|
50
|
+ QLabel* horiBearingPromptLabel_;
|
|
51
|
+ QLabel* horiAdvancePromptLabel_;
|
|
52
|
+ QLabel* vertBearingPromptLabel_;
|
|
53
|
+ QLabel* vertAdvancePromptLabel_;
|
|
54
|
+ QLabel* inkSizePromptLabel_;
|
|
55
|
+ QLabel* bitmapOffsetPromptLabel_;
|
|
56
|
+
|
|
57
|
+ QLabel* glyphIndexLabel_;
|
|
58
|
+ QLabel* charCodeLabel_;
|
|
59
|
+ QLabel* glyphNameLabel_;
|
|
60
|
+ QLabel* bboxSizeLabel_;
|
|
61
|
+ QLabel* horiBearingLabel_;
|
|
62
|
+ QLabel* horiAdvanceLabel_;
|
|
63
|
+ QLabel* vertBearingLabel_;
|
|
64
|
+ QLabel* vertAdvanceLabel_;
|
|
65
|
+ QLabel* inkSizeLabel_;
|
|
66
|
+ QLabel* bitmapOffsetLabel_;
|
|
67
|
+
|
|
68
|
+ GlyphBitmapWidget* bitmapWidget_;
|
|
69
|
+
|
|
70
|
+ QHBoxLayout* unitLayout_;
|
|
71
|
+ QGridLayout* layout_;
|
|
72
|
+
|
|
73
|
+ int dpi_;
|
|
74
|
+ FT_Glyph_Metrics fontUnitMetrics_, pixelMetrics_;
|
|
75
|
+
|
|
76
|
+ void createLayout();
|
|
77
|
+ void createConnections();
|
|
78
|
+
|
|
79
|
+ void changeUnit(int unitId);
|
|
80
|
+};
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+// end of glyphdetails.hpp |
src/ftinspect/rendering/glyphbitmap.cpp
... |
... |
@@ -9,25 +9,31 @@ |
9
|
9
|
#include "../engine/engine.hpp"
|
10
|
10
|
|
11
|
11
|
#include <cmath>
|
|
12
|
+#include <utility>
|
|
13
|
+#include <qevent.h>
|
12
|
14
|
#include <QPainter>
|
13
|
15
|
#include <QStyleOptionGraphicsItem>
|
14
|
16
|
#include <freetype/ftbitmap.h>
|
15
|
17
|
|
16
|
18
|
|
|
19
|
+GlyphBitmap::GlyphBitmap(QImage* image,
|
|
20
|
+ QRect rect)
|
|
21
|
+: image_(image),
|
|
22
|
+ boundingRect_(rect)
|
|
23
|
+{
|
|
24
|
+
|
|
25
|
+}
|
|
26
|
+
|
|
27
|
+
|
17
|
28
|
GlyphBitmap::GlyphBitmap(int glyphIndex,
|
18
|
29
|
FT_Glyph glyph,
|
19
|
30
|
Engine* engine)
|
20
|
31
|
{
|
21
|
32
|
QRect bRect;
|
22
|
|
- image_ = engine->tryDirectRenderColorLayers(glyphIndex, &bRect);
|
23
|
|
- if (image_)
|
24
|
|
- {
|
25
|
|
- bRect.setTop(-bRect.top());
|
26
|
|
- boundingRect_ = bRect; // QRect to QRectF
|
27
|
|
- return;
|
28
|
|
- }
|
|
33
|
+ image_ = engine->tryDirectRenderColorLayers(glyphIndex, &bRect, true);
|
29
|
34
|
|
30
|
|
- image_ = engine->convertGlyphToQImage(glyph, &bRect, true);
|
|
35
|
+ if (!image_)
|
|
36
|
+ image_ = engine->convertGlyphToQImage(glyph, &bRect, true);
|
31
|
37
|
boundingRect_ = bRect; // QRect to QRectF
|
32
|
38
|
}
|
33
|
39
|
|
... |
... |
@@ -60,8 +66,8 @@ GlyphBitmap::paint(QPainter* painter, |
60
|
66
|
image.convertToFormat(
|
61
|
67
|
QImage::Format_ARGB32_Premultiplied));
|
62
|
68
|
#else
|
63
|
|
- const qreal lod = option->levelOfDetailFromTransform(
|
64
|
|
- painter->worldTransform());
|
|
69
|
+ const qreal lod = QStyleOptionGraphicsItem::levelOfDetailFromTransform(
|
|
70
|
+ painter->worldTransform());
|
65
|
71
|
|
66
|
72
|
painter->setPen(Qt::NoPen);
|
67
|
73
|
|
... |
... |
@@ -85,4 +91,69 @@ GlyphBitmap::paint(QPainter* painter, |
85
|
91
|
}
|
86
|
92
|
|
87
|
93
|
|
|
94
|
+GlyphBitmapWidget::GlyphBitmapWidget(QWidget* parent)
|
|
95
|
+: QWidget(parent)
|
|
96
|
+{
|
|
97
|
+
|
|
98
|
+}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+GlyphBitmapWidget::~GlyphBitmapWidget()
|
|
102
|
+{
|
|
103
|
+ releaseImage();
|
|
104
|
+}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+void
|
|
108
|
+GlyphBitmapWidget::updateImage(QImage* image,
|
|
109
|
+ QRect rect)
|
|
110
|
+{
|
|
111
|
+ // XXX: really need to do this?
|
|
112
|
+ rect.moveTop(0);
|
|
113
|
+ rect.moveLeft(0);
|
|
114
|
+
|
|
115
|
+ delete bitmapItem_;
|
|
116
|
+ auto* copied = new QImage(image->copy());
|
|
117
|
+ bitmapItem_ = new GlyphBitmap(copied, rect);
|
|
118
|
+
|
|
119
|
+ repaint();
|
|
120
|
+}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+void
|
|
124
|
+GlyphBitmapWidget::releaseImage()
|
|
125
|
+{
|
|
126
|
+ delete bitmapItem_;
|
|
127
|
+ bitmapItem_ = NULL;
|
|
128
|
+ repaint();
|
|
129
|
+}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+void
|
|
133
|
+GlyphBitmapWidget::paintEvent(QPaintEvent* event)
|
|
134
|
+{
|
|
135
|
+ if (!bitmapItem_)
|
|
136
|
+ return;
|
|
137
|
+ auto s = size();
|
|
138
|
+ auto br = bitmapItem_->boundingRect();
|
|
139
|
+ double xScale = s.width() / br.width();
|
|
140
|
+ double yScale = s.height() / br.height();
|
|
141
|
+ auto scale = std::min(xScale, yScale);
|
|
142
|
+
|
|
143
|
+ QPainter painter(this);
|
|
144
|
+ painter.scale(scale, scale);
|
|
145
|
+
|
|
146
|
+ QStyleOptionGraphicsItem ogi;
|
|
147
|
+ ogi.exposedRect = br;
|
|
148
|
+ bitmapItem_->paint(&painter, &ogi, this);
|
|
149
|
+}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+QSize
|
|
153
|
+GlyphBitmapWidget::sizeHint() const
|
|
154
|
+{
|
|
155
|
+ return { 300, 300 };
|
|
156
|
+}
|
|
157
|
+
|
|
158
|
+
|
88
|
159
|
// end of glyphbitmap.cpp |
src/ftinspect/rendering/glyphbitmap.hpp
... |
... |
@@ -7,6 +7,8 @@ |
7
|
7
|
|
8
|
8
|
#include <QGraphicsItem>
|
9
|
9
|
#include <QPen>
|
|
10
|
+#include <QPaintEvent>
|
|
11
|
+#include <QWidget>
|
10
|
12
|
|
11
|
13
|
#include <ft2build.h>
|
12
|
14
|
#include <freetype/freetype.h>
|
... |
... |
@@ -20,6 +22,8 @@ class GlyphBitmap |
20
|
22
|
: public QGraphicsItem
|
21
|
23
|
{
|
22
|
24
|
public:
|
|
25
|
+ GlyphBitmap(QImage* image,
|
|
26
|
+ QRect rect);
|
23
|
27
|
GlyphBitmap(int glyphIndex,
|
24
|
28
|
FT_Glyph glyph,
|
25
|
29
|
Engine* engine);
|
... |
... |
@@ -34,5 +38,25 @@ private: |
34
|
38
|
QRectF boundingRect_;
|
35
|
39
|
};
|
36
|
40
|
|
|
41
|
+// Sometimes we don't want a complicated QGraphicsView
|
|
42
|
+// for this kind of work...
|
|
43
|
+class GlyphBitmapWidget
|
|
44
|
+: public QWidget
|
|
45
|
+{
|
|
46
|
+public:
|
|
47
|
+ GlyphBitmapWidget(QWidget* parent);
|
|
48
|
+ ~GlyphBitmapWidget() override;
|
|
49
|
+
|
|
50
|
+ void updateImage(QImage* image, QRect rect);
|
|
51
|
+ void releaseImage();
|
|
52
|
+
|
|
53
|
+protected:
|
|
54
|
+ void paintEvent(QPaintEvent* event) override;
|
|
55
|
+ QSize sizeHint() const override;
|
|
56
|
+
|
|
57
|
+private:
|
|
58
|
+ GlyphBitmap* bitmapItem_ = NULL;
|
|
59
|
+};
|
|
60
|
+
|
37
|
61
|
|
38
|
62
|
// end of glyphbitmap.hpp |
src/ftinspect/rendering/glyphcontinuous.cpp
... |
... |
@@ -197,7 +197,9 @@ GlyphContinuous::mouseReleaseEvent(QMouseEvent* event) |
197
|
197
|
auto dist = event->pos() - mouseDownPostition_;
|
198
|
198
|
if (dist.manhattanLength() < ClickDragThreshold)
|
199
|
199
|
{
|
200
|
|
- // TODO: clicked down, open overlay
|
|
200
|
+ auto gl = findGlyphByMouse(event->pos(), NULL);
|
|
201
|
+ if (gl)
|
|
202
|
+ emit updateGlyphDetails(gl, stringRenderer_.charMapIndex(), true);
|
201
|
203
|
}
|
202
|
204
|
}
|
203
|
205
|
else if (event->button() == Qt::RightButton)
|
... |
... |
@@ -222,9 +224,12 @@ GlyphContinuous::paintByRenderer() |
222
|
224
|
saveSingleGlyph(glyph, penPos, ctx);
|
223
|
225
|
});
|
224
|
226
|
stringRenderer_.setImageCallback(
|
225
|
|
- [&](QImage* image, QRect pos, FT_Vector advance, GlyphContext& ctx)
|
|
227
|
+ [&](QImage* image,
|
|
228
|
+ QRect pos,
|
|
229
|
+ FT_Vector penPos, FT_Vector advance,
|
|
230
|
+ GlyphContext& ctx)
|
226
|
231
|
{
|
227
|
|
- saveSingleGlyphImage(image, pos, advance, ctx);
|
|
232
|
+ saveSingleGlyphImage(image, pos, penPos, advance, ctx);
|
228
|
233
|
});
|
229
|
234
|
stringRenderer_.setPreprocessCallback(
|
230
|
235
|
[&](FT_Glyph* ptr)
|
... |
... |
@@ -413,12 +418,13 @@ GlyphContinuous::saveSingleGlyph(FT_Glyph glyph, |
413
|
418
|
if (!currentWritingLine_)
|
414
|
419
|
return;
|
415
|
420
|
|
416
|
|
- currentWritingLine_->entries.push_back(std::move(GlyphCacheEntry{}));
|
|
421
|
+ currentWritingLine_->entries.emplace_back();
|
417
|
422
|
auto& entry = currentWritingLine_->entries.back();
|
418
|
423
|
|
419
|
424
|
QRect rect;
|
420
|
|
- QImage* image = engine_->convertGlyphToQImage(glyph, &rect, false);
|
421
|
|
- rect.moveTop(height() - rect.top()); // TODO Don't place this here...
|
|
425
|
+ QImage* image = engine_->convertGlyphToQImage(glyph, &rect, true);
|
|
426
|
+ rect.translate(penPos.x, penPos.y);
|
|
427
|
+ //rect.moveTop(height() - rect.top()); // TODO Don't place this here...
|
422
|
428
|
|
423
|
429
|
entry.image = image;
|
424
|
430
|
entry.basePosition = rect;
|
... |
... |
@@ -433,21 +439,25 @@ GlyphContinuous::saveSingleGlyph(FT_Glyph glyph, |
433
|
439
|
|
434
|
440
|
void
|
435
|
441
|
GlyphContinuous::saveSingleGlyphImage(QImage* image,
|
436
|
|
- QRect pos,
|
|
442
|
+ QRect rect,
|
|
443
|
+ FT_Vector penPos,
|
437
|
444
|
FT_Vector advance,
|
438
|
445
|
GlyphContext gctx)
|
439
|
446
|
{
|
440
|
447
|
if (!currentWritingLine_)
|
441
|
448
|
return;
|
442
|
449
|
|
443
|
|
- currentWritingLine_->entries.push_back(GlyphCacheEntry{});
|
|
450
|
+ currentWritingLine_->entries.emplace_back();
|
444
|
451
|
auto& entry = currentWritingLine_->entries.back();
|
445
|
452
|
|
|
453
|
+ rect.translate(penPos.x, penPos.y);
|
|
454
|
+
|
446
|
455
|
entry.image = image;
|
447
|
|
- entry.basePosition = pos;
|
|
456
|
+ entry.basePosition = rect;
|
448
|
457
|
entry.charCode = gctx.charCode;
|
449
|
458
|
entry.glyphIndex = gctx.glyphIndex;
|
450
|
459
|
entry.advance = advance;
|
|
460
|
+ entry.penPos = { penPos.x, penPos.y };
|
451
|
461
|
}
|
452
|
462
|
|
453
|
463
|
|
src/ftinspect/rendering/glyphcontinuous.hpp
... |
... |
@@ -95,6 +95,7 @@ signals: |
95
|
95
|
void beginIndexChangeRequest(int newIndex);
|
96
|
96
|
void displayingCountUpdated(int newCount);
|
97
|
97
|
void rightClickGlyph(int glyphIndex, double sizePoint);
|
|
98
|
+ void updateGlyphDetails(GlyphCacheEntry* ctxt, int charMapIndex, bool open);
|
98
|
99
|
|
99
|
100
|
protected:
|
100
|
101
|
void paintEvent(QPaintEvent* event) override;
|
... |
... |
@@ -154,7 +155,8 @@ private: |
154
|
155
|
FT_Vector penPos,
|
155
|
156
|
GlyphContext gctx);
|
156
|
157
|
void saveSingleGlyphImage(QImage* image,
|
157
|
|
- QRect pos,
|
|
158
|
+ QRect rect,
|
|
159
|
+ FT_Vector penPos,
|
158
|
160
|
FT_Vector advance,
|
159
|
161
|
GlyphContext gctx);
|
160
|
162
|
void beginDrawCacheLine(QPainter* painter,
|
src/ftinspect/uihelper.cpp
... |
... |
@@ -26,4 +26,14 @@ setButtonNarrowest(QPushButton* btn) |
26
|
26
|
}
|
27
|
27
|
|
28
|
28
|
|
|
29
|
+void
|
|
30
|
+setLabelSelectable(QLabel* label)
|
|
31
|
+{
|
|
32
|
+
|
|
33
|
+ label->setTextInteractionFlags(Qt::TextSelectableByMouse
|
|
34
|
+ | Qt::TextSelectableByKeyboard);
|
|
35
|
+ label->setCursor(Qt::IBeamCursor);
|
|
36
|
+}
|
|
37
|
+
|
|
38
|
+
|
29
|
39
|
// end of uihelper.cpp |
src/ftinspect/uihelper.hpp
... |
... |
@@ -5,9 +5,11 @@ |
5
|
5
|
#pragma once
|
6
|
6
|
|
7
|
7
|
#include <QPushButton>
|
|
8
|
+#include <QLabel>
|
8
|
9
|
|
9
|
10
|
// we want buttons that are horizontally as small as possible
|
10
|
11
|
void setButtonNarrowest(QPushButton* btn);
|
|
12
|
+void setLabelSelectable(QLabel* label);
|
11
|
13
|
|
12
|
14
|
|
13
|
15
|
// end of uihelper.hpp |
|