Commits:
-
47238404
by Charlie Jiang
at 2022-09-04T00:23:30+08:00
[ftinspect] Rewrite `MainGUI`.
Note: This commit compiles, but the main view is removed, so you will get a
blank right panel. The singular view will be added back with major changes
in the next commit.
This commit mainly introduces below changes:
1. The original `MainGUI` contains almost all GUI elements. Most of them are
taken out to modular components. The current `MainGUI` serves only as
a skeleton provides coordinate between components, greatly shortened.
It also provides some auxiliary code such as calling to file chooser.
2. The left panel is moved to `SettingPanel` class. The current
`settingpanel.[ch]pp` are directly modified from the latest code, so they
contains some options not implemented in the `Engine`.
Structural code that is only added accompanying later change is removed,
such as the comparator mode. Such code will be added back with the
related feature. However, code for unimplemented options are simply
commented out.
3. The main part is transformed into a tabbed view. The original code is
removed. Refactored, it will be added back in the next commit.
4. The navigation buttons (Next/Prev Font/Face/NI) are changed into the new
triplet-selector, which is a major UI improvement.
* src/ftinspect/maingui.cpp, src/ftinspect/maingui.hpp: As described.
* src/ftinspect/panels/abstracttab.hpp: Add `AbstractTab` which is an
interface for all tabs listening for font reloading and repainting.
* src/ftinspect/panels/settingpanel.cpp,
src/ftinspect/panels/settingpanel.hpp:
As described, this is the left panel. This requires intensive reviewing
since many bugs had rooted here.
* src/ftinspect/widgets/tripletselector.cpp,
src/ftinspect/widgets/tripletselector.hpp:
As described, this is the triplet (Font/Subface/NI) selector.
This component is also responsible for repopulating triplet information
and keep up with the font file change (i.e. the
`FontFileManager::currentFileChanged` event is captured here).
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Add `fontValid` and `namedInstanceName` since `TripletSelector` requires
them. However, they'll subject to change later.
* src/ftinspect/ftinspect.cpp: Remove call to `MainGUI::setDefaults`.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
-
14556570
by Charlie Jiang
at 2022-09-04T00:23:36+08:00
[ftinspect] Add the `SingularTab` and related widgets.
This introduces the new singular tab. However, because the new tab heavily
depend on the new engine structure, it's current not functional. No bitmap
or outline will be displayed. This would be fixed after the `Engine` was
refactored in the next commit.
The new singular tab has the size and glyph index selector moved out as
modular widgets to be reused.
The new scroll and shortcut behaviours are introduced in this commit, which
depend on scroll events introduced in the custom `QGraphicsViewx`.
The infinity panning of grid is implemented mainly via
`SingularTab::updateGrid` and `Grid::updateRect`.
This commit is introducing new features since it would be unfavorable to
"backport" old version of glyph components, and add those new features in
future commits - this is way too complex.
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Add `currentFontNumberOfGlyphs` and `dpi` functions.
* src/ftinspect/widgets/fontsizeselector.cpp,
src/ftinspect/widgets/fontsizeselector.hpp:
This is the new font size selector to replace the old size/DPI/zoom boxes.
This widget is capable of handling wheel and key events delegated from
other widgets.
The support for fixed sizes and bitmap-only font is not yet added.
* src/ftinspect/widgets/glyphindexselector.cpp,
src/ftinspect/widgets/glyphindexselector.hpp:
This is the new glyph index selector to replace the old navi buttons.
This selector is aware of index min/max, consists of a group of navi
buttons, a text box (actually a spin box without buttons) to directly
input glyph index.
* src/ftinspect/glyphcomponents/graphicsdefault.cpp,
src/ftinspect/glyphcomponents/graphicsdefault.hpp:
This struct contains all default graphical settings (mainly for singular
view, e.g. the grid line color).
* src/ftinspect/maingui.cpp, src/ftinspect/maingui.hpp:
Add the new tab into the main window.
* src/ftinspect/glyphcomponents/glyphbitmap.cpp,
src/ftinspect/glyphcomponents/glyphbitmap.hpp:
This will now delegate rendering to the engine instead of doing rendering
itself. However, since the rendering part of the `Engine` is not
implemented, code initializing `image_` is left commented.
Also add another constructor for initializing directly from a `QImage`.
* src/ftinspect/glyphcomponents/glyphoutline.cpp,
src/ftinspect/glyphcomponents/glyphoutline.hpp,
src/ftinspect/glyphcomponents/glyphpointnumbers.cpp,
src/ftinspect/glyphcomponents/glyphpointnumbers.hpp,
src/ftinspect/glyphcomponents/glyphpoints.cpp,
src/ftinspect/glyphcomponents/glyphpoints.hpp:
Constructors of those items now accept a `FT_Glyph` instead of
`FT_Outline`. The conversion is done inside the view, and the view won't
be displayed if the glyph isn't outline glyph.
This simplifies the code of `SingularTab`.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
30 changed files:
Changes:
src/ftinspect/CMakeLists.txt
... |
... |
@@ -28,10 +28,17 @@ add_executable(ftinspect |
28
|
28
|
"glyphcomponents/glyphpointnumbers.cpp"
|
29
|
29
|
"glyphcomponents/glyphpoints.cpp"
|
30
|
30
|
"glyphcomponents/grid.cpp"
|
|
31
|
+ "glyphcomponents/graphicsdefault.cpp"
|
31
|
32
|
|
32
|
33
|
"widgets/customwidgets.cpp"
|
|
34
|
+ "widgets/tripletselector.cpp"
|
|
35
|
+ "widgets/glyphindexselector.cpp"
|
|
36
|
+ "widgets/fontsizeselector.cpp"
|
33
|
37
|
|
34
|
38
|
"models/customcomboboxmodels.cpp"
|
|
39
|
+
|
|
40
|
+ "panels/settingpanel.cpp"
|
|
41
|
+ "panels/singular.cpp"
|
35
|
42
|
)
|
36
|
43
|
target_link_libraries(ftinspect
|
37
|
44
|
Qt5::Core Qt5::Widgets
|
src/ftinspect/engine/engine.cpp
... |
... |
@@ -237,6 +237,50 @@ Engine::numberOfNamedInstances(int fontIndex, |
237
|
237
|
}
|
238
|
238
|
|
239
|
239
|
|
|
240
|
+QString
|
|
241
|
+Engine::namedInstanceName(int fontIndex, long faceIndex, int index)
|
|
242
|
+{
|
|
243
|
+ if (fontIndex < 0)
|
|
244
|
+ return {};
|
|
245
|
+
|
|
246
|
+ FT_Face face;
|
|
247
|
+ QString name;
|
|
248
|
+
|
|
249
|
+ // search triplet (fontIndex, faceIndex, index)
|
|
250
|
+ FTC_FaceID ftcFaceID = reinterpret_cast<FTC_FaceID>
|
|
251
|
+ (faceIDMap_.value(FaceID(fontIndex,
|
|
252
|
+ faceIndex,
|
|
253
|
+ index)));
|
|
254
|
+ if (ftcFaceID)
|
|
255
|
+ {
|
|
256
|
+ // found
|
|
257
|
+ if (!FTC_Manager_LookupFace(cacheManager_, ftcFaceID, &face))
|
|
258
|
+ name = QString("%1 %2")
|
|
259
|
+ .arg(face->family_name)
|
|
260
|
+ .arg(face->style_name);
|
|
261
|
+ }
|
|
262
|
+ else
|
|
263
|
+ {
|
|
264
|
+ // not found; try to load triplet (fontIndex, faceIndex, index)
|
|
265
|
+ ftcFaceID = reinterpret_cast<FTC_FaceID>(faceCounter_);
|
|
266
|
+ faceIDMap_.insert(FaceID(fontIndex, faceIndex, index),
|
|
267
|
+ faceCounter_++);
|
|
268
|
+
|
|
269
|
+ if (!FTC_Manager_LookupFace(cacheManager_, ftcFaceID, &face))
|
|
270
|
+ name = QString("%1 %2")
|
|
271
|
+ .arg(face->family_name)
|
|
272
|
+ .arg(face->style_name);
|
|
273
|
+ else
|
|
274
|
+ {
|
|
275
|
+ faceIDMap_.remove(FaceID(fontIndex, faceIndex, 0));
|
|
276
|
+ faceCounter_--;
|
|
277
|
+ }
|
|
278
|
+ }
|
|
279
|
+
|
|
280
|
+ return name;
|
|
281
|
+}
|
|
282
|
+
|
|
283
|
+
|
240
|
284
|
int
|
241
|
285
|
Engine::loadFont(int fontIndex,
|
242
|
286
|
long faceIndex,
|
... |
... |
@@ -299,6 +343,7 @@ Engine::loadFont(int fontIndex, |
299
|
343
|
fontType_ = FontType_TrueType;
|
300
|
344
|
}
|
301
|
345
|
|
|
346
|
+ curNumGlyphs_ = numGlyphs;
|
302
|
347
|
return numGlyphs;
|
303
|
348
|
}
|
304
|
349
|
|
... |
... |
@@ -394,6 +439,14 @@ Engine::numberOfOpenedFonts() |
394
|
439
|
}
|
395
|
440
|
|
396
|
441
|
|
|
442
|
+bool
|
|
443
|
+Engine::fontValid()
|
|
444
|
+{
|
|
445
|
+ // TODO: use fallback font
|
|
446
|
+ return ftSize_ != NULL;
|
|
447
|
+}
|
|
448
|
+
|
|
449
|
+
|
397
|
450
|
void
|
398
|
451
|
Engine::openFonts(QStringList fontFileNames)
|
399
|
452
|
{
|
src/ftinspect/engine/engine.hpp
... |
... |
@@ -85,13 +85,20 @@ public: |
85
|
85
|
int numberOfOpenedFonts();
|
86
|
86
|
|
87
|
87
|
// (for current fonts)
|
|
88
|
+ bool fontValid();
|
88
|
89
|
int currentFontType() const { return fontType_; }
|
89
|
90
|
const QString& currentFamilyName() { return curFamilyName_; }
|
90
|
91
|
const QString& currentStyleName() { return curStyleName_; }
|
|
92
|
+ int currentFontNumberOfGlyphs() { return curNumGlyphs_; }
|
|
93
|
+
|
91
|
94
|
QString glyphName(int glyphIndex);
|
92
|
95
|
long numberOfFaces(int fontIndex);
|
93
|
96
|
int numberOfNamedInstances(int fontIndex,
|
94
|
97
|
long faceIndex);
|
|
98
|
+ QString namedInstanceName(int fontIndex, long faceIndex, int index);
|
|
99
|
+
|
|
100
|
+ // (settings)
|
|
101
|
+ int dpi() { return dpi_; }
|
95
|
102
|
|
96
|
103
|
//////// Setters (direct or indirect)
|
97
|
104
|
|
... |
... |
@@ -138,6 +145,7 @@ private: |
138
|
145
|
|
139
|
146
|
QString curFamilyName_;
|
140
|
147
|
QString curStyleName_;
|
|
148
|
+ int curNumGlyphs_ = -1;
|
141
|
149
|
|
142
|
150
|
FT_Library library_;
|
143
|
151
|
FTC_Manager cacheManager_;
|
src/ftinspect/ftinspect.cpp
... |
... |
@@ -23,7 +23,6 @@ main(int argc, |
23
|
23
|
|
24
|
24
|
Engine engine;
|
25
|
25
|
MainGUI gui(&engine);
|
26
|
|
- gui.setDefaults();
|
27
|
26
|
|
28
|
27
|
gui.show();
|
29
|
28
|
|
src/ftinspect/glyphcomponents/glyphbitmap.cpp
... |
... |
@@ -5,47 +5,44 @@ |
5
|
5
|
|
6
|
6
|
#include "glyphbitmap.hpp"
|
7
|
7
|
|
|
8
|
+#include "../engine/engine.hpp"
|
|
9
|
+
|
8
|
10
|
#include <cmath>
|
|
11
|
+#include <utility>
|
|
12
|
+#include <qevent.h>
|
9
|
13
|
#include <QPainter>
|
10
|
14
|
#include <QStyleOptionGraphicsItem>
|
|
15
|
+#include <freetype/ftbitmap.h>
|
11
|
16
|
|
12
|
17
|
|
13
|
|
-GlyphBitmap::GlyphBitmap(FT_Outline* outline,
|
14
|
|
- FT_Library lib,
|
15
|
|
- FT_Pixel_Mode pxlMode,
|
16
|
|
- const QVector<QRgb>& monoColorTbl,
|
17
|
|
- const QVector<QRgb>& grayColorTbl)
|
18
|
|
-: library_(lib),
|
19
|
|
- pixelMode_(pxlMode),
|
20
|
|
- monoColorTable_(monoColorTbl),
|
21
|
|
- grayColorTable_(grayColorTbl)
|
|
18
|
+GlyphBitmap::GlyphBitmap(QImage* image,
|
|
19
|
+ QRect rect)
|
|
20
|
+: image_(image),
|
|
21
|
+ boundingRect_(rect)
|
22
|
22
|
{
|
23
|
|
- // make a copy of the outline since we are going to manipulate it
|
24
|
|
- FT_Outline_New(library_,
|
25
|
|
- static_cast<unsigned int>(outline->n_points),
|
26
|
|
- outline->n_contours,
|
27
|
|
- &transformed_);
|
28
|
|
- FT_Outline_Copy(outline, &transformed_);
|
29
|
|
-
|
30
|
|
- FT_BBox cbox;
|
31
|
|
- FT_Outline_Get_CBox(outline, &cbox);
|
32
|
|
-
|
33
|
|
- cbox.xMin &= ~63;
|
34
|
|
- cbox.yMin &= ~63;
|
35
|
|
- cbox.xMax = (cbox.xMax + 63) & ~63;
|
36
|
|
- cbox.yMax = (cbox.yMax + 63) & ~63;
|
37
|
|
-
|
38
|
|
- // we shift the outline to the origin for rendering later on
|
39
|
|
- FT_Outline_Translate(&transformed_, -cbox.xMin, -cbox.yMin);
|
40
|
|
-
|
41
|
|
- boundingRect_.setCoords(cbox.xMin / 64, -cbox.yMax / 64,
|
42
|
|
- cbox.xMax / 64, -cbox.yMin / 64);
|
|
23
|
+
|
|
24
|
+}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+GlyphBitmap::GlyphBitmap(int glyphIndex,
|
|
28
|
+ FT_Glyph glyph,
|
|
29
|
+ Engine* engine)
|
|
30
|
+{
|
|
31
|
+ QRect bRect;
|
|
32
|
+ image_ = NULL; // TODO: refactr Engine
|
|
33
|
+ //image_ = engine->renderingEngine()->tryDirectRenderColorLayers(glyphIndex,
|
|
34
|
+ // &bRect, true);
|
|
35
|
+
|
|
36
|
+ //if (!image_)
|
|
37
|
+ // image_ = engine->renderingEngine()->convertGlyphToQImage(glyph, &bRect,
|
|
38
|
+ // true);
|
|
39
|
+ boundingRect_ = bRect; // QRect to QRectF
|
43
|
40
|
}
|
44
|
41
|
|
45
|
42
|
|
46
|
43
|
GlyphBitmap::~GlyphBitmap()
|
47
|
44
|
{
|
48
|
|
- FT_Outline_Done(library_, &transformed_);
|
|
45
|
+ delete image_;
|
49
|
46
|
}
|
50
|
47
|
|
51
|
48
|
QRectF
|
... |
... |
@@ -60,40 +57,9 @@ GlyphBitmap::paint(QPainter* painter, |
60
|
57
|
const QStyleOptionGraphicsItem* option,
|
61
|
58
|
QWidget*)
|
62
|
59
|
{
|
63
|
|
- FT_Bitmap bitmap;
|
64
|
|
-
|
65
|
|
- int height = static_cast<int>(ceil(boundingRect_.height()));
|
66
|
|
- int width = static_cast<int>(ceil(boundingRect_.width()));
|
67
|
|
- QImage::Format format = QImage::Format_Indexed8;
|
68
|
|
-
|
69
|
|
- // XXX cover LCD and color
|
70
|
|
- if (pixelMode_ == FT_PIXEL_MODE_MONO)
|
71
|
|
- format = QImage::Format_Mono;
|
72
|
|
-
|
73
|
|
- QImage image(QSize(width, height), format);
|
74
|
|
-
|
75
|
|
- if (pixelMode_ == FT_PIXEL_MODE_MONO)
|
76
|
|
- image.setColorTable(monoColorTable_);
|
77
|
|
- else
|
78
|
|
- image.setColorTable(grayColorTable_);
|
79
|
|
-
|
80
|
|
- image.fill(0);
|
81
|
|
-
|
82
|
|
- bitmap.rows = static_cast<unsigned int>(height);
|
83
|
|
- bitmap.width = static_cast<unsigned int>(width);
|
84
|
|
- bitmap.buffer = image.bits();
|
85
|
|
- bitmap.pitch = image.bytesPerLine();
|
86
|
|
- bitmap.pixel_mode = pixelMode_;
|
87
|
|
-
|
88
|
|
- FT_Error error = FT_Outline_Get_Bitmap(library_,
|
89
|
|
- &transformed_,
|
90
|
|
- &bitmap);
|
91
|
|
- if (error)
|
92
|
|
- {
|
93
|
|
- // XXX error handling
|
|
60
|
+ if (!image_)
|
94
|
61
|
return;
|
95
|
|
- }
|
96
|
|
-
|
|
62
|
+
|
97
|
63
|
// `drawImage' doesn't work as expected:
|
98
|
64
|
// the larger the zoom, the more the pixel rectangle positions
|
99
|
65
|
// deviate from the grid lines
|
... |
... |
@@ -102,16 +68,16 @@ GlyphBitmap::paint(QPainter* painter, |
102
|
68
|
image.convertToFormat(
|
103
|
69
|
QImage::Format_ARGB32_Premultiplied));
|
104
|
70
|
#else
|
105
|
|
- const qreal lod = option->levelOfDetailFromTransform(
|
106
|
|
- painter->worldTransform());
|
|
71
|
+ const qreal lod = QStyleOptionGraphicsItem::levelOfDetailFromTransform(
|
|
72
|
+ painter->worldTransform());
|
107
|
73
|
|
108
|
74
|
painter->setPen(Qt::NoPen);
|
109
|
75
|
|
110
|
|
- for (int x = 0; x < image.width(); x++)
|
111
|
|
- for (int y = 0; y < image.height(); y++)
|
|
76
|
+ for (int x = 0; x < image_->width(); x++)
|
|
77
|
+ for (int y = 0; y < image_->height(); y++)
|
112
|
78
|
{
|
113
|
79
|
// be careful not to lose the alpha channel
|
114
|
|
- QRgb p = image.pixel(x, y);
|
|
80
|
+ QRgb p = image_->pixel(x, y);
|
115
|
81
|
painter->fillRect(QRectF(x + boundingRect_.left() - 1 / lod / 2,
|
116
|
82
|
y + boundingRect_.top() - 1 / lod / 2,
|
117
|
83
|
1 + 1 / lod,
|
src/ftinspect/glyphcomponents/glyphbitmap.hpp
... |
... |
@@ -7,33 +7,34 @@ |
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>
|
|
15
|
+#include <freetype/ftglyph.h>
|
13
|
16
|
#include <freetype/ftoutln.h>
|
14
|
17
|
|
15
|
18
|
|
|
19
|
+class Engine;
|
|
20
|
+
|
16
|
21
|
class GlyphBitmap
|
17
|
22
|
: public QGraphicsItem
|
18
|
23
|
{
|
19
|
24
|
public:
|
20
|
|
- GlyphBitmap(FT_Outline* outline,
|
21
|
|
- FT_Library library,
|
22
|
|
- FT_Pixel_Mode pixelMode,
|
23
|
|
- const QVector<QRgb>& monoColorTable,
|
24
|
|
- const QVector<QRgb>& grayColorTable);
|
25
|
|
- ~GlyphBitmap();
|
26
|
|
- QRectF boundingRect() const;
|
|
25
|
+ GlyphBitmap(QImage* image,
|
|
26
|
+ QRect rect);
|
|
27
|
+ GlyphBitmap(int glyphIndex,
|
|
28
|
+ FT_Glyph glyph,
|
|
29
|
+ Engine* engine);
|
|
30
|
+ ~GlyphBitmap() override;
|
|
31
|
+ QRectF boundingRect() const override;
|
27
|
32
|
void paint(QPainter* painter,
|
28
|
33
|
const QStyleOptionGraphicsItem* option,
|
29
|
|
- QWidget* widget);
|
|
34
|
+ QWidget* widget) override;
|
30
|
35
|
|
31
|
36
|
private:
|
32
|
|
- FT_Outline transformed_;
|
33
|
|
- FT_Library library_;
|
34
|
|
- unsigned char pixelMode_;
|
35
|
|
- const QVector<QRgb>& monoColorTable_;
|
36
|
|
- const QVector<QRgb>& grayColorTable_;
|
|
37
|
+ QImage* image_ = NULL;
|
37
|
38
|
QRectF boundingRect_;
|
38
|
39
|
};
|
39
|
40
|
|
src/ftinspect/glyphcomponents/glyphoutline.cpp
... |
... |
@@ -87,11 +87,17 @@ static FT_Outline_Funcs outlineFuncs = |
87
|
87
|
} // extern "C"
|
88
|
88
|
|
89
|
89
|
|
90
|
|
-GlyphOutline::GlyphOutline(const QPen& outlineP,
|
91
|
|
- FT_Outline* outln)
|
92
|
|
-: outlinePen_(outlineP),
|
93
|
|
- outline_(outln)
|
|
90
|
+GlyphOutline::GlyphOutline(const QPen& pen,
|
|
91
|
+ FT_Glyph glyph)
|
|
92
|
+: outlinePen_(pen)
|
94
|
93
|
{
|
|
94
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
95
|
+ {
|
|
96
|
+ outline_ = NULL;
|
|
97
|
+ return;
|
|
98
|
+ }
|
|
99
|
+ outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
100
|
+
|
95
|
101
|
FT_BBox cbox;
|
96
|
102
|
|
97
|
103
|
qreal halfPenWidth = outlinePen_.widthF();
|
... |
... |
@@ -117,6 +123,8 @@ GlyphOutline::paint(QPainter* painter, |
117
|
123
|
const QStyleOptionGraphicsItem*,
|
118
|
124
|
QWidget*)
|
119
|
125
|
{
|
|
126
|
+ if (!outline_)
|
|
127
|
+ return;
|
120
|
128
|
painter->setPen(outlinePen_);
|
121
|
129
|
|
122
|
130
|
QPainterPath path;
|
src/ftinspect/glyphcomponents/glyphoutline.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
... |
... |
@@ -18,11 +19,11 @@ class GlyphOutline |
18
|
19
|
{
|
19
|
20
|
public:
|
20
|
21
|
GlyphOutline(const QPen& pen,
|
21
|
|
- FT_Outline* outline);
|
22
|
|
- QRectF boundingRect() const;
|
|
22
|
+ FT_Glyph glyph);
|
|
23
|
+ QRectF boundingRect() const override;
|
23
|
24
|
void paint(QPainter* painter,
|
24
|
25
|
const QStyleOptionGraphicsItem* option,
|
25
|
|
- QWidget* widget);
|
|
26
|
+ QWidget* widget) override;
|
26
|
27
|
|
27
|
28
|
private:
|
28
|
29
|
QPen outlinePen_;
|
src/ftinspect/glyphcomponents/glyphpointnumbers.cpp
... |
... |
@@ -12,11 +12,17 @@ |
12
|
12
|
|
13
|
13
|
GlyphPointNumbers::GlyphPointNumbers(const QPen& onP,
|
14
|
14
|
const QPen& offP,
|
15
|
|
- FT_Outline* outln)
|
|
15
|
+ FT_Glyph glyph)
|
16
|
16
|
: onPen_(onP),
|
17
|
|
- offPen_(offP),
|
18
|
|
- outline_(outln)
|
|
17
|
+ offPen_(offP)
|
19
|
18
|
{
|
|
19
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
20
|
+ {
|
|
21
|
+ outline_ = NULL;
|
|
22
|
+ return;
|
|
23
|
+ }
|
|
24
|
+ outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
25
|
+
|
20
|
26
|
FT_BBox cbox;
|
21
|
27
|
|
22
|
28
|
FT_Outline_Get_CBox(outline_, &cbox);
|
... |
... |
@@ -41,6 +47,8 @@ GlyphPointNumbers::paint(QPainter* painter, |
41
|
47
|
const QStyleOptionGraphicsItem* option,
|
42
|
48
|
QWidget*)
|
43
|
49
|
{
|
|
50
|
+ if (!outline_)
|
|
51
|
+ return;
|
44
|
52
|
const qreal lod = option->levelOfDetailFromTransform(
|
45
|
53
|
painter->worldTransform());
|
46
|
54
|
|
src/ftinspect/glyphcomponents/glyphpointnumbers.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
... |
... |
@@ -19,11 +20,11 @@ class GlyphPointNumbers |
19
|
20
|
public:
|
20
|
21
|
GlyphPointNumbers(const QPen& onPen,
|
21
|
22
|
const QPen& offPen,
|
22
|
|
- FT_Outline* outline);
|
23
|
|
- QRectF boundingRect() const;
|
|
23
|
+ FT_Glyph glyph);
|
|
24
|
+ QRectF boundingRect() const override;
|
24
|
25
|
void paint(QPainter* painter,
|
25
|
26
|
const QStyleOptionGraphicsItem* option,
|
26
|
|
- QWidget* widget);
|
|
27
|
+ QWidget* widget) override;
|
27
|
28
|
|
28
|
29
|
private:
|
29
|
30
|
QPen onPen_;
|
src/ftinspect/glyphcomponents/glyphpoints.cpp
... |
... |
@@ -11,11 +11,17 @@ |
11
|
11
|
|
12
|
12
|
GlyphPoints::GlyphPoints(const QPen& onP,
|
13
|
13
|
const QPen& offP,
|
14
|
|
- FT_Outline* outln)
|
|
14
|
+ FT_Glyph glyph)
|
15
|
15
|
: onPen_(onP),
|
16
|
|
- offPen_(offP),
|
17
|
|
- outline_(outln)
|
|
16
|
+ offPen_(offP)
|
18
|
17
|
{
|
|
18
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
19
|
+ {
|
|
20
|
+ outline_ = NULL;
|
|
21
|
+ return;
|
|
22
|
+ }
|
|
23
|
+ outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
24
|
+
|
19
|
25
|
FT_BBox cbox;
|
20
|
26
|
|
21
|
27
|
qreal halfPenWidth = qMax(onPen_.widthF(), offPen_.widthF()) / 2;
|
... |
... |
@@ -41,6 +47,9 @@ GlyphPoints::paint(QPainter* painter, |
41
|
47
|
const QStyleOptionGraphicsItem* option,
|
42
|
48
|
QWidget*)
|
43
|
49
|
{
|
|
50
|
+ if (!outline_)
|
|
51
|
+ return;
|
|
52
|
+
|
44
|
53
|
const qreal lod = option->levelOfDetailFromTransform(
|
45
|
54
|
painter->worldTransform());
|
46
|
55
|
|
src/ftinspect/glyphcomponents/glyphpoints.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
... |
... |
@@ -19,11 +20,11 @@ class GlyphPoints |
19
|
20
|
public:
|
20
|
21
|
GlyphPoints(const QPen& onPen,
|
21
|
22
|
const QPen& offPen,
|
22
|
|
- FT_Outline* outline);
|
23
|
|
- QRectF boundingRect() const;
|
|
23
|
+ FT_Glyph glyph);
|
|
24
|
+ QRectF boundingRect() const override;
|
24
|
25
|
void paint(QPainter* painter,
|
25
|
26
|
const QStyleOptionGraphicsItem* option,
|
26
|
|
- QWidget* widget);
|
|
27
|
+ QWidget* widget) override;
|
27
|
28
|
|
28
|
29
|
private:
|
29
|
30
|
QPen onPen_;
|
src/ftinspect/glyphcomponents/graphicsdefault.cpp
|
1
|
+// graphicsdefault.cpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#include "graphicsdefault.hpp"
|
|
6
|
+
|
|
7
|
+GraphicsDefault* GraphicsDefault::instance_ = NULL;
|
|
8
|
+
|
|
9
|
+GraphicsDefault::GraphicsDefault()
|
|
10
|
+{
|
|
11
|
+ // XXX make this user-configurable
|
|
12
|
+
|
|
13
|
+ axisPen.setColor(Qt::black);
|
|
14
|
+ axisPen.setWidth(0);
|
|
15
|
+ blueZonePen.setColor(QColor(64, 64, 255, 64)); // light blue
|
|
16
|
+ blueZonePen.setWidth(0);
|
|
17
|
+ // Don't make this solid
|
|
18
|
+ gridPen.setColor(QColor(0, 0, 0, 255 - QColor(Qt::lightGray).red()));
|
|
19
|
+ gridPen.setWidth(0);
|
|
20
|
+ offPen.setColor(Qt::darkGreen);
|
|
21
|
+ offPen.setWidth(3);
|
|
22
|
+ onPen.setColor(Qt::red);
|
|
23
|
+ onPen.setWidth(3);
|
|
24
|
+ outlinePen.setColor(Qt::red);
|
|
25
|
+ outlinePen.setWidth(0);
|
|
26
|
+ segmentPen.setColor(QColor(64, 255, 128, 64)); // light green
|
|
27
|
+ segmentPen.setWidth(0);
|
|
28
|
+
|
|
29
|
+ advanceAuxPen.setColor(QColor(110, 52, 235)); // kind of blue
|
|
30
|
+ advanceAuxPen.setWidth(0);
|
|
31
|
+ ascDescAuxPen.setColor(QColor(255, 0, 0)); // red
|
|
32
|
+ ascDescAuxPen.setWidth(0);
|
|
33
|
+}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+GraphicsDefault*
|
|
37
|
+GraphicsDefault::deafultInstance()
|
|
38
|
+{
|
|
39
|
+ if (!instance_)
|
|
40
|
+ instance_ = new GraphicsDefault;
|
|
41
|
+
|
|
42
|
+ return instance_;
|
|
43
|
+}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+// end of graphicsdefault.cpp |
src/ftinspect/glyphcomponents/graphicsdefault.hpp
|
1
|
+// graphicsdefault.hpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2022 by Charlie Jiang.
|
|
4
|
+
|
|
5
|
+#pragma once
|
|
6
|
+
|
|
7
|
+#include <QVector>
|
|
8
|
+#include <QRgb>
|
|
9
|
+#include <QPen>
|
|
10
|
+
|
|
11
|
+// This is default graphics objects fed into render functions.
|
|
12
|
+struct GraphicsDefault
|
|
13
|
+{
|
|
14
|
+ QPen axisPen;
|
|
15
|
+ QPen blueZonePen;
|
|
16
|
+ QPen gridPen;
|
|
17
|
+ QPen offPen;
|
|
18
|
+ QPen onPen;
|
|
19
|
+ QPen outlinePen;
|
|
20
|
+ QPen segmentPen;
|
|
21
|
+
|
|
22
|
+ QPen advanceAuxPen;
|
|
23
|
+ QPen ascDescAuxPen;
|
|
24
|
+
|
|
25
|
+ GraphicsDefault();
|
|
26
|
+
|
|
27
|
+ static GraphicsDefault* deafultInstance();
|
|
28
|
+
|
|
29
|
+private:
|
|
30
|
+ static GraphicsDefault* instance_;
|
|
31
|
+};
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+// end of graphicsdefault.hpp |
src/ftinspect/glyphcomponents/grid.cpp
... |
... |
@@ -5,88 +5,131 @@ |
5
|
5
|
|
6
|
6
|
#include "grid.hpp"
|
7
|
7
|
|
|
8
|
+#include "graphicsdefault.hpp"
|
|
9
|
+
|
8
|
10
|
#include <QPainter>
|
9
|
11
|
#include <QStyleOptionGraphicsItem>
|
|
12
|
+#include <QGraphicsWidget>
|
|
13
|
+#include <QGraphicsView>
|
10
|
14
|
|
11
|
15
|
|
12
|
|
-Grid::Grid(const QPen& gridP,
|
13
|
|
- const QPen& axisP)
|
14
|
|
-: gridPen_(gridP),
|
15
|
|
- axisPen_(axisP)
|
|
16
|
+Grid::Grid(QGraphicsView* parentView)
|
|
17
|
+: parentView_(parentView)
|
16
|
18
|
{
|
17
|
19
|
// empty
|
|
20
|
+ updateRect();
|
18
|
21
|
}
|
19
|
22
|
|
20
|
23
|
|
21
|
24
|
QRectF
|
22
|
25
|
Grid::boundingRect() const
|
23
|
26
|
{
|
24
|
|
- // XXX fix size
|
|
27
|
+ return rect_;
|
|
28
|
+}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+void
|
|
32
|
+Grid::updateRect()
|
|
33
|
+{
|
|
34
|
+ auto viewport = parentView_->mapToScene(parentView_->viewport()->geometry())
|
|
35
|
+ .boundingRect()
|
|
36
|
+ .toRect();
|
|
37
|
+ int minX = std::min(viewport.left() - 10, -100);
|
|
38
|
+ int minY = std::min(viewport.top() - 10, -100);
|
|
39
|
+ int maxX = std::max(viewport.right() + 10, 100);
|
|
40
|
+ int maxY = std::max(viewport.bottom() + 10, 100);
|
|
41
|
+
|
|
42
|
+ auto newSceneRect = QRectF(QPointF(minX - 20, minY - 20),
|
|
43
|
+ QPointF(maxX + 20, maxY + 20));
|
|
44
|
+ if (sceneRect_ != newSceneRect && scene())
|
|
45
|
+ {
|
|
46
|
+ scene()->setSceneRect(newSceneRect);
|
|
47
|
+ sceneRect_ = newSceneRect;
|
|
48
|
+ }
|
25
|
49
|
|
26
|
50
|
// no need to take care of pen width
|
27
|
|
- return QRectF(-100, -100,
|
28
|
|
- 200, 200);
|
|
51
|
+ rect_ = QRectF(QPointF(minX, minY),
|
|
52
|
+ QPointF(maxX, maxY));
|
29
|
53
|
}
|
30
|
54
|
|
31
|
55
|
|
32
|
|
-// XXX call this in a `myQDraphicsView::drawBackground' derived method
|
33
|
|
-// to always fill the complete viewport
|
34
|
|
-
|
35
|
56
|
void
|
36
|
57
|
Grid::paint(QPainter* painter,
|
37
|
58
|
const QStyleOptionGraphicsItem* option,
|
38
|
|
- QWidget*)
|
|
59
|
+ QWidget* widget)
|
39
|
60
|
{
|
|
61
|
+ auto gb = GraphicsDefault::deafultInstance();
|
|
62
|
+ auto br = boundingRect().toRect();
|
|
63
|
+ int minX = br.left();
|
|
64
|
+ int minY = br.top();
|
|
65
|
+ int maxX = br.right();
|
|
66
|
+ int maxY = br.bottom();
|
|
67
|
+
|
40
|
68
|
const qreal lod = option->levelOfDetailFromTransform(
|
41
|
69
|
painter->worldTransform());
|
42
|
|
-
|
43
|
|
- painter->setPen(gridPen_);
|
44
|
|
-
|
45
|
|
- // don't mark pixel center with a cross if magnification is too small
|
46
|
|
- if (lod > 20)
|
|
70
|
+ if (showGrid_)
|
47
|
71
|
{
|
48
|
|
- int halfLength = 1;
|
49
|
|
-
|
50
|
|
- // cf. QSpinBoxx
|
51
|
|
- if (lod > 640)
|
52
|
|
- halfLength = 6;
|
53
|
|
- else if (lod > 320)
|
54
|
|
- halfLength = 5;
|
55
|
|
- else if (lod > 160)
|
56
|
|
- halfLength = 4;
|
57
|
|
- else if (lod > 80)
|
58
|
|
- halfLength = 3;
|
59
|
|
- else if (lod > 40)
|
60
|
|
- halfLength = 2;
|
61
|
|
-
|
62
|
|
- for (qreal x = -100; x < 100; x++)
|
63
|
|
- for (qreal y = -100; y < 100; y++)
|
64
|
|
- {
|
65
|
|
- painter->drawLine(QLineF(x + 0.5, y + 0.5 - halfLength / lod,
|
66
|
|
- x + 0.5, y + 0.5 + halfLength / lod));
|
67
|
|
- painter->drawLine(QLineF(x + 0.5 - halfLength / lod, y + 0.5,
|
68
|
|
- x + 0.5 + halfLength / lod, y + 0.5));
|
69
|
|
- }
|
|
72
|
+ painter->setPen(gb->gridPen);
|
|
73
|
+
|
|
74
|
+ // don't mark pixel center with a cross if magnification is too small
|
|
75
|
+ if (lod > 20)
|
|
76
|
+ {
|
|
77
|
+ int halfLength = 1;
|
|
78
|
+
|
|
79
|
+ // cf. QSpinBoxx
|
|
80
|
+ if (lod > 640)
|
|
81
|
+ halfLength = 6;
|
|
82
|
+ else if (lod > 320)
|
|
83
|
+ halfLength = 5;
|
|
84
|
+ else if (lod > 160)
|
|
85
|
+ halfLength = 4;
|
|
86
|
+ else if (lod > 80)
|
|
87
|
+ halfLength = 3;
|
|
88
|
+ else if (lod > 40)
|
|
89
|
+ halfLength = 2;
|
|
90
|
+
|
|
91
|
+ for (qreal x = minX; x < maxX; x++)
|
|
92
|
+ for (qreal y = minY; y < maxY; y++)
|
|
93
|
+ {
|
|
94
|
+ painter->drawLine(QLineF(x + 0.5, y + 0.5 - halfLength / lod,
|
|
95
|
+ x + 0.5, y + 0.5 + halfLength / lod));
|
|
96
|
+ painter->drawLine(QLineF(x + 0.5 - halfLength / lod, y + 0.5,
|
|
97
|
+ x + 0.5 + halfLength / lod, y + 0.5));
|
|
98
|
+ }
|
|
99
|
+ }
|
|
100
|
+
|
|
101
|
+ // don't draw grid if magnification is too small
|
|
102
|
+ if (lod >= 5)
|
|
103
|
+ {
|
|
104
|
+ for (int x = minX; x <= maxX; x++)
|
|
105
|
+ painter->drawLine(x, minY,
|
|
106
|
+ x, maxY);
|
|
107
|
+ for (int y = minY; y <= maxY; y++)
|
|
108
|
+ painter->drawLine(minX, y,
|
|
109
|
+ maxX, y);
|
|
110
|
+ }
|
|
111
|
+
|
|
112
|
+ painter->setPen(gb->axisPen);
|
|
113
|
+
|
|
114
|
+ painter->drawLine(0, minY,
|
|
115
|
+ 0, maxY);
|
|
116
|
+ painter->drawLine(minX, 0,
|
|
117
|
+ maxX, 0);
|
70
|
118
|
}
|
71
|
119
|
|
72
|
|
- // don't draw grid if magnification is too small
|
73
|
|
- if (lod >= 5)
|
|
120
|
+ if (showAuxLines_)
|
74
|
121
|
{
|
75
|
|
- // XXX fix size
|
76
|
|
- for (int x = -100; x <= 100; x++)
|
77
|
|
- painter->drawLine(x, -100,
|
78
|
|
- x, 100);
|
79
|
|
- for (int y = -100; y <= 100; y++)
|
80
|
|
- painter->drawLine(-100, y,
|
81
|
|
- 100, y);
|
|
122
|
+ // TODO: impl
|
82
|
123
|
}
|
|
124
|
+}
|
83
|
125
|
|
84
|
|
- painter->setPen(axisPen_);
|
85
|
126
|
|
86
|
|
- painter->drawLine(0, -100,
|
87
|
|
- 0, 100);
|
88
|
|
- painter->drawLine(-100, 0,
|
89
|
|
- 100, 0);
|
|
127
|
+void
|
|
128
|
+Grid::setShowGrid(bool showGrid, bool showAuxLines)
|
|
129
|
+{
|
|
130
|
+ showGrid_ = showGrid;
|
|
131
|
+ showAuxLines_ = showAuxLines;
|
|
132
|
+ update();
|
90
|
133
|
}
|
91
|
134
|
|
92
|
135
|
|
src/ftinspect/glyphcomponents/grid.hpp
... |
... |
@@ -6,23 +6,30 @@ |
6
|
6
|
#pragma once
|
7
|
7
|
|
8
|
8
|
#include <QGraphicsItem>
|
|
9
|
+#include <QGraphicsView>
|
9
|
10
|
#include <QPen>
|
10
|
11
|
|
11
|
|
-
|
12
|
12
|
class Grid
|
13
|
13
|
: public QGraphicsItem
|
14
|
14
|
{
|
15
|
15
|
public:
|
16
|
|
- Grid(const QPen& gridPen,
|
17
|
|
- const QPen& axisPen);
|
18
|
|
- QRectF boundingRect() const;
|
|
16
|
+ Grid(QGraphicsView* parentView);
|
|
17
|
+ QRectF boundingRect() const override;
|
19
|
18
|
void paint(QPainter* painter,
|
20
|
19
|
const QStyleOptionGraphicsItem* option,
|
21
|
|
- QWidget* widget);
|
|
20
|
+ QWidget* widget) override;
|
|
21
|
+
|
|
22
|
+ void setShowGrid(bool showGrid, bool showAuxLines);
|
|
23
|
+
|
|
24
|
+ void updateRect(); // there's no signal/slots for QGraphicsItem.
|
22
|
25
|
|
23
|
26
|
private:
|
24
|
|
- QPen gridPen_;
|
25
|
|
- QPen axisPen_;
|
|
27
|
+ QGraphicsView* parentView_;
|
|
28
|
+ QRectF rect_;
|
|
29
|
+ QRectF sceneRect_;
|
|
30
|
+
|
|
31
|
+ bool showGrid_ = true;
|
|
32
|
+ bool showAuxLines_ = false;
|
26
|
33
|
};
|
27
|
34
|
|
28
|
35
|
|
src/ftinspect/maingui.cpp
|
1
|
+// maingui.cpp
|
|
2
|
+
|
|
3
|
+// Copyright (C) 2016-2022 by Werner Lemberg.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+#include "maingui.hpp"
|
|
7
|
+
|
|
8
|
+#include <QApplication>
|
|
9
|
+#include <QFileDialog>
|
|
10
|
+#include <QMessageBox>
|
|
11
|
+#include <QSettings>
|
|
12
|
+#include <QScrollBar>
|
|
13
|
+#include <QStatusBar>
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+MainGUI::MainGUI(Engine* engine)
|
|
17
|
+: engine_(engine)
|
|
18
|
+{
|
|
19
|
+ createLayout();
|
|
20
|
+ createConnections();
|
|
21
|
+ createActions();
|
|
22
|
+ createMenus();
|
|
23
|
+
|
|
24
|
+ readSettings();
|
|
25
|
+ setUnifiedTitleAndToolBarOnMac(true);
|
|
26
|
+
|
|
27
|
+ show();
|
|
28
|
+}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+MainGUI::~MainGUI()
|
|
32
|
+{
|
|
33
|
+ // empty
|
|
34
|
+}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+// overloading
|
|
38
|
+
|
|
39
|
+void
|
|
40
|
+MainGUI::closeEvent(QCloseEvent* event)
|
|
41
|
+{
|
|
42
|
+ writeSettings();
|
|
43
|
+ event->accept();
|
|
44
|
+}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+void
|
|
48
|
+MainGUI::keyPressEvent(QKeyEvent* event)
|
|
49
|
+{
|
|
50
|
+ // Delegate key events to tabs
|
|
51
|
+ if (!tabWidget_->currentWidget()->eventFilter(this, event))
|
|
52
|
+ QMainWindow::keyPressEvent(event);
|
|
53
|
+}
|
|
54
|
+
|
|
55
|
+
|
| |