freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Git][freetype/freetype-demos][gsoc-2022-chariri-final] 2 commits: [ftin


From: Charlie Jiang (@cqjjjzr)
Subject: [Git][freetype/freetype-demos][gsoc-2022-chariri-final] 2 commits: [ftinspect] Rewrite `MainGUI`.
Date: Sat, 03 Sep 2022 16:26:04 +0000

Charlie Jiang pushed to branch gsoc-2022-chariri-final at FreeType / FreeType Demo Programs

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
    +
    
    56
    +void
    
    57
    +MainGUI::about()
    
    58
    +{
    
    59
    +  QMessageBox::about(
    
    60
    +    this,
    
    61
    +    tr("About ftinspect"),
    
    62
    +    tr("<p>This is <b>ftinspect</b> version %1<br>"
    
    63
    +       " Copyright %2 2016-2022<br>"
    
    64
    +       " by Werner Lemberg <tt>&lt;wl@gnu.org&gt;</tt></p>"
    
    65
    +       ""
    
    66
    +       "<p><b>ftinspect</b> shows how a font gets rendered"
    
    67
    +       " by FreeType, allowing control over virtually"
    
    68
    +       " all rendering parameters.</p>"
    
    69
    +       ""
    
    70
    +       "<p>License:"
    
    71
    +       " <a href=''>FreeType"
    
    72
    +       " License (FTL)</a> or"
    
    73
    +       " <a href=''>GNU"
    
    74
    +       " GPLv2</a></p>")
    
    75
    +       .arg(QApplication::applicationVersion())
    
    76
    +       .arg(QChar(0xA9)));
    
    77
    +}
    
    78
    +
    
    79
    +
    
    80
    +void
    
    81
    +MainGUI::aboutQt()
    
    82
    +{
    
    83
    +  QApplication::aboutQt();
    
    84
    +}
    
    85
    +
    
    86
    +
    
    87
    +void
    
    88
    +MainGUI::loadFonts()
    
    89
    +{
    
    90
    +  QStringList files = QFileDialog::getOpenFileNames(
    
    91
    +                        this,
    
    92
    +                        tr("Load one or more fonts"),
    
    93
    +                        QDir::homePath(),
    
    94
    +                        "",
    
    95
    +                        NULL,
    
    96
    +                        QFileDialog::ReadOnly);
    
    97
    +  openFonts(files);
    
    98
    +}
    
    99
    +
    
    100
    +
    
    101
    +void
    
    102
    +MainGUI::openFonts(QStringList const& fileNames)
    
    103
    +{
    
    104
    +  engine_->openFonts(fileNames);
    
    105
    +  tripletSelector_->repopulateFonts();
    
    106
    +}
    
    107
    +
    
    108
    +
    
    109
    +void
    
    110
    +MainGUI::onTripletChanged()
    
    111
    +{
    
    112
    +  auto state = settingPanel_->blockSignals(true);
    
    113
    +  settingPanel_->onFontChanged();
    
    114
    +  settingPanel_->blockSignals(state);
    
    115
    +  reloadCurrentTabFont();
    
    116
    +}
    
    117
    +
    
    118
    +
    
    119
    +void
    
    120
    +MainGUI::switchTab()
    
    121
    +{
    
    122
    +  reloadCurrentTabFont();
    
    123
    +  lastTab_ = tabWidget_->currentWidget();
    
    124
    +}
    
    125
    +
    
    126
    +
    
    127
    +void
    
    128
    +MainGUI::repaintCurrentTab()
    
    129
    +{
    
    130
    +  applySettings();
    
    131
    +  tabs_[tabWidget_->currentIndex()]->repaintGlyph();
    
    132
    +}
    
    133
    +
    
    134
    +
    
    135
    +void
    
    136
    +MainGUI::reloadCurrentTabFont()
    
    137
    +{
    
    138
    +  engine_->resetCache();
    
    139
    +  applySettings();
    
    140
    +  auto index = tabWidget_->currentIndex();
    
    141
    +  if (index >= 0 && static_cast<size_t>(index) < tabs_.size())
    
    142
    +    tabs_[index]->reloadFont();
    
    143
    +}
    
    144
    +
    
    145
    +
    
    146
    +void
    
    147
    +MainGUI::applySettings()
    
    148
    +{
    
    149
    +  settingPanel_->applySettings();
    
    150
    +  settingPanel_->applyDelayedSettings();
    
    151
    +}
    
    152
    +
    
    153
    +
    
    154
    +// XXX distances are specified in pixels,
    
    155
    +//     making the layout dependent on the output device resolution
    
    156
    +void
    
    157
    +MainGUI::createLayout()
    
    158
    +{
    
    159
    +  // left side
    
    160
    +  settingPanel_ = new SettingPanel(this, engine_);
    
    161
    +
    
    162
    +  leftLayout_ = new QVBoxLayout; // The only point is to set a margin->remove?
    
    163
    +  leftLayout_->addWidget(settingPanel_);
    
    164
    +  leftLayout_->setContentsMargins(32, 32, 0, 16);
    
    165
    +
    
    166
    +  // we don't want to expand the left side horizontally;
    
    167
    +  // to change the policy we have to use a widget wrapper
    
    168
    +  leftWidget_ = new QWidget(this);
    
    169
    +  leftWidget_->setLayout(leftLayout_);
    
    170
    +  leftWidget_->setMaximumWidth(400);
    
    171
    +
    
    172
    +  // right side
    
    173
    +  singularTab_ = new SingularTab(this, engine_);
    
    174
    +
    
    175
    +  tabWidget_ = new QTabWidget(this);
    
    176
    +  tabWidget_->setObjectName("mainTab"); // for stylesheet
    
    177
    +
    
    178
    +  // Note those two list must be in sync
    
    179
    +  tabs_.push_back(singularTab_);
    
    180
    +  tabWidget_->addTab(singularTab_, tr("Singular Grid View"));
    
    181
    +  lastTab_ = singularTab_;
    
    182
    +  
    
    183
    +  tabWidget_->setTabToolTip(0, tr("View single glyph in grid view.\n"
    
    184
    +                                  "For pixelwise inspection of the glyphs."));
    
    185
    +  tripletSelector_ = new TripletSelector(this, engine_);
    
    186
    +
    
    187
    +  rightLayout_ = new QVBoxLayout;
    
    188
    +  //rightLayout_->addWidget(fontNameLabel_);
    
    189
    +  rightLayout_->addWidget(tabWidget_); // same for `leftLayout_`: Remove?
    
    190
    +  rightLayout_->setContentsMargins(16, 32, 32, 16);
    
    191
    +
    
    192
    +  // for symmetry with the left side use a widget also
    
    193
    +  rightWidget_ = new QWidget(this);
    
    194
    +  rightWidget_->setLayout(rightLayout_);
    
    195
    +
    
    196
    +  // the whole thing
    
    197
    +  mainPartLayout_ = new QHBoxLayout;
    
    198
    +  mainPartLayout_->addWidget(leftWidget_);
    
    199
    +  mainPartLayout_->addWidget(rightWidget_);
    
    200
    +
    
    201
    +  ftinspectLayout_ = new QVBoxLayout;
    
    202
    +  ftinspectLayout_->setSpacing(0);
    
    203
    +  ftinspectLayout_->addLayout(mainPartLayout_);
    
    204
    +  ftinspectLayout_->addWidget(tripletSelector_);
    
    205
    +  ftinspectLayout_->setContentsMargins(0, 0, 0, 0);
    
    206
    +
    
    207
    +  ftinspectWidget_ = new QWidget(this);
    
    208
    +  ftinspectWidget_->setLayout(ftinspectLayout_);
    
    209
    +
    
    210
    +  ftinspectLayout_->setSizeConstraint(QLayout::SetNoConstraint);
    
    211
    +  layout()->setSizeConstraint(QLayout::SetNoConstraint);
    
    212
    +  resize(ftinspectWidget_->minimumSizeHint().width(),
    
    213
    +         700 * logicalDpiY() / 96);
    
    214
    +
    
    215
    +  statusBar()->hide(); // remove the extra space
    
    216
    +  setCentralWidget(ftinspectWidget_);
    
    217
    +  setWindowTitle("ftinspect");
    
    218
    +}
    
    219
    +
    
    220
    +
    
    221
    +void
    
    222
    +MainGUI::createConnections()
    
    223
    +{
    
    224
    +  connect(settingPanel_, &SettingPanel::fontReloadNeeded,
    
    225
    +          this, &MainGUI::reloadCurrentTabFont);
    
    226
    +  connect(settingPanel_, &SettingPanel::repaintNeeded,
    
    227
    +          this, &MainGUI::repaintCurrentTab);
    
    228
    +
    
    229
    +  connect(tabWidget_, &QTabWidget::currentChanged,
    
    230
    +          this, &MainGUI::switchTab);
    
    231
    +
    
    232
    +  connect(tripletSelector_, &TripletSelector::tripletChanged,
    
    233
    +          this, &MainGUI::onTripletChanged);
    
    234
    +}
    
    235
    +
    
    236
    +
    
    237
    +void
    
    238
    +MainGUI::createActions()
    
    239
    +{
    
    240
    +  loadFontsAct_ = new QAction(tr("&Load Fonts"), this);
    
    241
    +  loadFontsAct_->setShortcuts(QKeySequence::Open);
    
    242
    +  connect(loadFontsAct_, &QAction::triggered, this, &MainGUI::loadFonts);
    
    243
    +
    
    244
    +  closeFontAct_ = new QAction(tr("&Close Font"), this);
    
    245
    +  closeFontAct_->setShortcuts(QKeySequence::Close);
    
    246
    +  connect(closeFontAct_, &QAction::triggered,
    
    247
    +          tripletSelector_, &TripletSelector::closeCurrentFont);
    
    248
    +
    
    249
    +  exitAct_ = new QAction(tr("E&xit"), this);
    
    250
    +  exitAct_->setShortcuts(QKeySequence::Quit);
    
    251
    +  connect(exitAct_, &QAction::triggered, this, &MainGUI::close);
    
    252
    +
    
    253
    +  aboutAct_ = new QAction(tr("&About"), this);
    
    254
    +  connect(aboutAct_, &QAction::triggered, this, &MainGUI::about);
    
    255
    +
    
    256
    +  aboutQtAct_ = new QAction(tr("About &Qt"), this);
    
    257
    +  connect(aboutQtAct_, &QAction::triggered, this, &MainGUI::aboutQt);
    
    258
    +}
    
    259
    +
    
    260
    +
    
    261
    +void
    
    262
    +MainGUI::createMenus()
    
    263
    +{
    
    264
    +  menuFile_ = menuBar()->addMenu(tr("&File"));
    
    265
    +  menuFile_->addAction(loadFontsAct_);
    
    266
    +  menuFile_->addAction(closeFontAct_);
    
    267
    +  menuFile_->addAction(exitAct_);
    
    268
    +
    
    269
    +  menuHelp_ = menuBar()->addMenu(tr("&Help"));
    
    270
    +  menuHelp_->addAction(aboutAct_);
    
    271
    +  menuHelp_->addAction(aboutQtAct_);
    
    272
    +}
    
    273
    +
    
    274
    +
    
    275
    +void
    
    276
    +MainGUI::readSettings()
    
    277
    +{
    
    278
    +  QSettings settings;
    
    279
    +//  QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
    
    280
    +//  QSize size = settings.value("size", QSize(400, 400)).toSize();
    
    281
    +//  resize(size);
    
    282
    +//  move(pos);
    
    283
    +}
    
    284
    +
    
    285
    +
    
    286
    +void
    
    287
    +MainGUI::writeSettings()
    
    288
    +{
    
    289
    +  QSettings settings;
    
    290
    +//  settings.setValue("pos", pos());
    
    291
    +//  settings.setValue("size", size());
    
    292
    +}
    
    293
    +
    
    294
    +
    
    295
    +// end of maingui.cpp

  • src/ftinspect/maingui.hpp
    1
    +// maingui.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2016-2022 by Werner Lemberg.
    
    4
    +
    
    5
    +
    
    6
    +#pragma once
    
    7
    +
    
    8
    +#include "engine/engine.hpp"
    
    9
    +#include "widgets/tripletselector.hpp"
    
    10
    +#include "panels/settingpanel.hpp"
    
    11
    +#include "panels/abstracttab.hpp"
    
    12
    +#include "panels/singular.hpp"
    
    13
    +
    
    14
    +#include <vector>
    
    15
    +#include <QAction>
    
    16
    +#include <QCloseEvent>
    
    17
    +#include <QGridLayout>
    
    18
    +#include <QDockWidget>
    
    19
    +#include <QBoxLayout>
    
    20
    +#include <QLabel>
    
    21
    +#include <QMainWindow>
    
    22
    +#include <QMenu>
    
    23
    +#include <QMenuBar>
    
    24
    +#include <QTabWidget>
    
    25
    +
    
    26
    +
    
    27
    +class MainGUI
    
    28
    +: public QMainWindow
    
    29
    +{
    
    30
    +  Q_OBJECT
    
    31
    +
    
    32
    +public:
    
    33
    +  MainGUI(Engine* engine);
    
    34
    +  ~MainGUI() override;
    
    35
    +
    
    36
    +  friend class Engine;
    
    37
    +  friend FT_Error faceRequester(FTC_FaceID,
    
    38
    +                                FT_Library,
    
    39
    +                                FT_Pointer,
    
    40
    +                                FT_Face*);
    
    41
    +
    
    42
    +protected:
    
    43
    +  void closeEvent(QCloseEvent*) override;
    
    44
    +  void keyPressEvent(QKeyEvent* event) override;
    
    45
    +
    
    46
    +private slots:
    
    47
    +  void about();
    
    48
    +  void aboutQt();
    
    49
    +  void repaintCurrentTab();
    
    50
    +  void reloadCurrentTabFont();
    
    51
    +  void loadFonts();
    
    52
    +  void onTripletChanged();
    
    53
    +  void switchTab();
    
    54
    +
    
    55
    +private:
    
    56
    +  Engine* engine_;
    
    57
    +  
    
    58
    +  int currentNumberOfGlyphs_;
    
    59
    +
    
    60
    +  // layout related stuff
    
    61
    +  QAction *aboutAct_;
    
    62
    +  QAction *aboutQtAct_;
    
    63
    +  QAction *closeFontAct_;
    
    64
    +  QAction *exitAct_;
    
    65
    +  QAction *loadFontsAct_;
    
    66
    +
    
    67
    +  QVBoxLayout *ftinspectLayout_;
    
    68
    +  QHBoxLayout *mainPartLayout_;
    
    69
    +
    
    70
    +  QLocale *locale_;
    
    71
    +
    
    72
    +  QMenu *menuFile_;
    
    73
    +  QMenu *menuHelp_;
    
    74
    +  
    
    75
    +  TripletSelector* tripletSelector_;
    
    76
    +  
    
    77
    +  QVBoxLayout *leftLayout_;
    
    78
    +  QVBoxLayout *rightLayout_;
    
    79
    +
    
    80
    +  QWidget *ftinspectWidget_;
    
    81
    +  QWidget *leftWidget_;
    
    82
    +  QWidget *rightWidget_;
    
    83
    +
    
    84
    +  SettingPanel* settingPanel_;
    
    85
    +
    
    86
    +  QTabWidget* tabWidget_;
    
    87
    +  std::vector<AbstractTab*> tabs_;
    
    88
    +  SingularTab* singularTab_;
    
    89
    +  QWidget* lastTab_ = NULL;
    
    90
    +
    
    91
    +  void openFonts(QStringList const& fileNames);
    
    92
    +
    
    93
    +  void applySettings();
    
    94
    +
    
    95
    +  void createActions();
    
    96
    +  void createConnections();
    
    97
    +  void createLayout();
    
    98
    +  void createMenus();
    
    99
    +
    
    100
    +  void readSettings();
    
    101
    +  void writeSettings();
    
    102
    +};
    
    103
    +
    
    104
    +
    
    105
    +// end of maingui.hpp

  • src/ftinspect/meson.build
    ... ... @@ -29,11 +29,18 @@ if qt5_dep.found()
    29 29
         'glyphcomponents/glyphpointnumbers.cpp',
    
    30 30
         'glyphcomponents/glyphpoints.cpp',
    
    31 31
         'glyphcomponents/grid.cpp',
    
    32
    +    'glyphcomponents/graphicsdefault.cpp',
    
    32 33
     
    
    33 34
         'widgets/customwidgets.cpp',
    
    35
    +    'widgets/tripletselector.cpp',
    
    36
    +    'widgets/glyphindexselector.cpp',
    
    37
    +    'widgets/fontsizeselector.cpp',
    
    34 38
     
    
    35 39
         'models/customcomboboxmodels.cpp',
    
    36 40
     
    
    41
    +    'panels/settingpanel.cpp',
    
    42
    +    'panels/singular.cpp',
    
    43
    +
    
    37 44
         'ftinspect.cpp',
    
    38 45
         'maingui.cpp',
    
    39 46
         'uihelper.cpp',
    
    ... ... @@ -43,8 +50,13 @@ if qt5_dep.found()
    43 50
         moc_headers: [
    
    44 51
           'engine/fontfilemanager.hpp',
    
    45 52
           'widgets/customwidgets.hpp',
    
    53
    +      'widgets/tripletselector.hpp',
    
    54
    +      'widgets/glyphindexselector.hpp',
    
    55
    +      'widgets/fontsizeselector.hpp',
    
    46 56
           'maingui.hpp',
    
    47 57
           'models/customcomboboxmodels.hpp',
    
    58
    +      'panels/settingpanel.hpp',
    
    59
    +      'panels/singular.hpp',
    
    48 60
         ],
    
    49 61
         dependencies: qt5_dep)
    
    50 62
     
    

  • src/ftinspect/panels/abstracttab.hpp
    1
    +// abstracttab.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +// This is an pure abstract interface for a ftinspect "tab".
    
    8
    +// The interface itself does not inherit from `QWidget`, but should be used as
    
    9
    +// the second base class.
    
    10
    +class AbstractTab
    
    11
    +{
    
    12
    +public:
    
    13
    +  virtual ~AbstractTab() = default; // must be `virtual` for `dynamic_cast`
    
    14
    +  
    
    15
    +  virtual void repaintGlyph() = 0;
    
    16
    +  virtual void reloadFont() = 0;
    
    17
    +};
    
    18
    +
    
    19
    +
    
    20
    +// end of abstracttab.hpp

  • src/ftinspect/panels/settingpanel.cpp
    1
    +// settingpanel.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "settingpanel.hpp"
    
    6
    +
    
    7
    +#include "../uihelper.hpp"
    
    8
    +
    
    9
    +#include <QColorDialog>
    
    10
    +
    
    11
    +// for `FT_DEBUG_AUTOFIT`
    
    12
    +#include <freetype/config/ftoption.h>
    
    13
    +
    
    14
    +SettingPanel::SettingPanel(QWidget* parent,
    
    15
    +                           Engine* engine)
    
    16
    +: QWidget(parent),
    
    17
    +  engine_(engine)
    
    18
    +{
    
    19
    +#ifdef FT_DEBUG_AUTOFIT
    
    20
    +  debugMode_ = !comparatorMode_;
    
    21
    +#else
    
    22
    +  debugMode_ = false;
    
    23
    +#endif
    
    24
    +  createLayout();
    
    25
    +  setDefaults();
    
    26
    +  createConnections();
    
    27
    +  checkAllSettings();
    
    28
    +}
    
    29
    +
    
    30
    +
    
    31
    +int
    
    32
    +SettingPanel::antiAliasingModeIndex()
    
    33
    +{
    
    34
    +  return antiAliasingComboBox_->currentIndex();
    
    35
    +}
    
    36
    +
    
    37
    +
    
    38
    +bool
    
    39
    +SettingPanel::kerningEnabled()
    
    40
    +{
    
    41
    +  return kerningCheckBox_->isChecked();
    
    42
    +}
    
    43
    +
    
    44
    +
    
    45
    +bool
    
    46
    +SettingPanel::lsbRsbDeltaEnabled()
    
    47
    +{
    
    48
    +  return lsbRsbDeltaCheckBox_->isChecked();
    
    49
    +}
    
    50
    +
    
    51
    +
    
    52
    +void
    
    53
    +SettingPanel::populatePalettes()
    
    54
    +{
    
    55
    +  // TODO: Impl
    
    56
    +}
    
    57
    +
    
    58
    +
    
    59
    +void
    
    60
    +SettingPanel::checkAllSettings()
    
    61
    +{
    
    62
    +  onFontChanged();
    
    63
    +  checkAntiAliasing();
    
    64
    +}
    
    65
    +
    
    66
    +
    
    67
    +void
    
    68
    +SettingPanel::checkHinting()
    
    69
    +{
    
    70
    +  if (hintingCheckBox_->isChecked())
    
    71
    +  {
    
    72
    +    // TODO: tricky: disable auto-hinting
    
    73
    +    checkAutoHinting(); // this will emit repaint
    
    74
    +  }
    
    75
    +  else
    
    76
    +  {
    
    77
    +    hintingModeLabel_->setEnabled(false);
    
    78
    +    hintingModeComboBox_->setEnabled(false);
    
    79
    +
    
    80
    +    autoHintingCheckBox_->setEnabled(false);
    
    81
    +    if (debugMode_)
    
    82
    +    {
    
    83
    +      horizontalHintingCheckBox_->setEnabled(false);
    
    84
    +      verticalHintingCheckBox_->setEnabled(false);
    
    85
    +      blueZoneHintingCheckBox_->setEnabled(false);
    
    86
    +      segmentDrawingCheckBox_->setEnabled(false);
    
    87
    +    }
    
    88
    +
    
    89
    +    stemDarkeningCheckBox_->setEnabled(false);
    
    90
    +    antiAliasingComboBoxModel_->setLightAntiAliasingEnabled(false);
    
    91
    +    auto aaMode = antiAliasingComboBox_->currentIndex();
    
    92
    +    if (aaMode == AntiAliasingComboBoxModel::AntiAliasing_Light
    
    93
    +        || aaMode == AntiAliasingComboBoxModel::AntiAliasing_Light_SubPixel)
    
    94
    +      antiAliasingComboBox_->setCurrentIndex(
    
    95
    +        AntiAliasingComboBoxModel::AntiAliasing_Normal);
    
    96
    +    
    
    97
    +    emit repaintNeeded();
    
    98
    +  }
    
    99
    +}
    
    100
    +
    
    101
    +
    
    102
    +void
    
    103
    +SettingPanel::checkHintingMode()
    
    104
    +{
    
    105
    +  //if (!comparatorMode_)
    
    106
    +  //  applyDelayedSettings();
    
    107
    +
    
    108
    +  emit fontReloadNeeded();
    
    109
    +}
    
    110
    +
    
    111
    +
    
    112
    +void
    
    113
    +SettingPanel::checkAutoHinting()
    
    114
    +{
    
    115
    +  if (autoHintingCheckBox_->isChecked())
    
    116
    +  {
    
    117
    +    hintingModeLabel_->setEnabled(false);
    
    118
    +    hintingModeComboBox_->setEnabled(false);
    
    119
    +
    
    120
    +    if (debugMode_)
    
    121
    +    {
    
    122
    +      horizontalHintingCheckBox_->setEnabled(true);
    
    123
    +      verticalHintingCheckBox_->setEnabled(true);
    
    124
    +      blueZoneHintingCheckBox_->setEnabled(true);
    
    125
    +      segmentDrawingCheckBox_->setEnabled(true);
    
    126
    +    }
    
    127
    +
    
    128
    +    antiAliasingComboBoxModel_->setLightAntiAliasingEnabled(true);
    
    129
    +    auto aaMode = antiAliasingComboBox_->currentIndex();
    
    130
    +    stemDarkeningCheckBox_->setEnabled(
    
    131
    +      aaMode == AntiAliasingComboBoxModel::AntiAliasing_Light
    
    132
    +      || aaMode == AntiAliasingComboBoxModel::AntiAliasing_Light_SubPixel);
    
    133
    +  }
    
    134
    +  else
    
    135
    +  {
    
    136
    +    if (engine_->currentFontType() == Engine::FontType_CFF
    
    137
    +        || engine_->currentFontType() == Engine::FontType_TrueType)
    
    138
    +    {
    
    139
    +      hintingModeLabel_->setEnabled(true);
    
    140
    +      hintingModeComboBox_->setEnabled(true);
    
    141
    +    }
    
    142
    +
    
    143
    +    if (debugMode_)
    
    144
    +    {
    
    145
    +      horizontalHintingCheckBox_->setEnabled(false);
    
    146
    +      verticalHintingCheckBox_->setEnabled(false);
    
    147
    +      blueZoneHintingCheckBox_->setEnabled(false);
    
    148
    +      segmentDrawingCheckBox_->setEnabled(false);
    
    149
    +    }
    
    150
    +
    
    151
    +    antiAliasingComboBoxModel_->setLightAntiAliasingEnabled(false);
    
    152
    +    stemDarkeningCheckBox_->setEnabled(false);
    
    153
    +
    
    154
    +    auto aaMode = antiAliasingComboBox_->currentIndex();
    
    155
    +    if (aaMode == AntiAliasingComboBoxModel::AntiAliasing_Light
    
    156
    +        || aaMode == AntiAliasingComboBoxModel::AntiAliasing_Light_SubPixel)
    
    157
    +      antiAliasingComboBox_->setCurrentIndex(
    
    158
    +          AntiAliasingComboBoxModel::AntiAliasing_Normal);
    
    159
    +  }
    
    160
    +  emit repaintNeeded();
    
    161
    +}
    
    162
    +
    
    163
    +
    
    164
    +void
    
    165
    +SettingPanel::checkAntiAliasing()
    
    166
    +{
    
    167
    +  int index = antiAliasingComboBox_->currentIndex();
    
    168
    +  auto isMono = index == AntiAliasingComboBoxModel::AntiAliasing_None;
    
    169
    +  auto isLight
    
    170
    +    = index == AntiAliasingComboBoxModel::AntiAliasing_Light
    
    171
    +      || index == AntiAliasingComboBoxModel::AntiAliasing_Light_SubPixel;
    
    172
    +  auto disableLCD
    
    173
    +    = index == AntiAliasingComboBoxModel::AntiAliasing_None
    
    174
    +      || index == AntiAliasingComboBoxModel::AntiAliasing::AntiAliasing_Normal
    
    175
    +      || isLight;
    
    176
    +
    
    177
    +  lcdFilterLabel_->setEnabled(!disableLCD);
    
    178
    +  lcdFilterComboBox_->setEnabled(!disableLCD);
    
    179
    +  stemDarkeningCheckBox_->setEnabled(isLight);
    
    180
    +  gammaSlider_->setEnabled(!isMono);
    
    181
    +
    
    182
    +  emit repaintNeeded();
    
    183
    +}
    
    184
    +
    
    185
    +
    
    186
    +void
    
    187
    +SettingPanel::checkPalette()
    
    188
    +{
    
    189
    +  paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked());
    
    190
    +  emit repaintNeeded();
    
    191
    +}
    
    192
    +
    
    193
    +
    
    194
    +void
    
    195
    +SettingPanel::checkStemDarkening()
    
    196
    +{
    
    197
    +  //if (!comparatorMode_)
    
    198
    +  //  applyDelayedSettings();
    
    199
    +
    
    200
    +  emit fontReloadNeeded();
    
    201
    +}
    
    202
    +
    
    203
    +
    
    204
    +void
    
    205
    +SettingPanel::openBackgroundPicker()
    
    206
    +{
    
    207
    +  auto result = QColorDialog::getColor(backgroundColor_, 
    
    208
    +                                       this,
    
    209
    +                                       tr("Background Color"));
    
    210
    +  if (result.isValid())
    
    211
    +  {
    
    212
    +    backgroundColor_ = result;
    
    213
    +    resetColorBlocks();
    
    214
    +    emit repaintNeeded();
    
    215
    +  }
    
    216
    +}
    
    217
    +
    
    218
    +
    
    219
    +void
    
    220
    +SettingPanel::openForegroundPicker()
    
    221
    +{
    
    222
    +  auto result = QColorDialog::getColor(foregroundColor_, 
    
    223
    +                                       this,
    
    224
    +                                       tr("Foreground Color"),
    
    225
    +                                       QColorDialog::ShowAlphaChannel);
    
    226
    +  if (result.isValid())
    
    227
    +  {
    
    228
    +    foregroundColor_ = result;
    
    229
    +    resetColorBlocks();
    
    230
    +    emit repaintNeeded();
    
    231
    +  }
    
    232
    +}
    
    233
    +
    
    234
    +
    
    235
    +void
    
    236
    +SettingPanel::updateGamma()
    
    237
    +{
    
    238
    +  gammaValueLabel_->setText(QString::number(gammaSlider_->value() / 10.0,
    
    239
    +                           'f',
    
    240
    +                           1));
    
    241
    +  emit repaintNeeded();
    
    242
    +}
    
    243
    +
    
    244
    +
    
    245
    +void
    
    246
    +SettingPanel::resetColorBlocks()
    
    247
    +{
    
    248
    +  foregroundBlock_->setStyleSheet(
    
    249
    +    QString("QWidget {background-color: rgba(%1, %2, %3, %4);}")
    
    250
    +      .arg(foregroundColor_.red())
    
    251
    +      .arg(foregroundColor_.green())
    
    252
    +      .arg(foregroundColor_.blue())
    
    253
    +      .arg(foregroundColor_.alpha()));
    
    254
    +  backgroundBlock_->setStyleSheet(
    
    255
    +    QString("QWidget {background-color: rgba(%1, %2, %3, %4);}")
    
    256
    +      .arg(backgroundColor_.red())
    
    257
    +      .arg(backgroundColor_.green())
    
    258
    +      .arg(backgroundColor_.blue())
    
    259
    +      .arg(backgroundColor_.alpha()));
    
    260
    +}
    
    261
    +
    
    262
    +
    
    263
    +void
    
    264
    +SettingPanel::onFontChanged()
    
    265
    +{
    
    266
    +  auto blockState = blockSignals(signalsBlocked());
    
    267
    +  
    
    268
    +  if (engine_->currentFontType() == Engine::FontType_CFF)
    
    269
    +  {
    
    270
    +    hintingModeComboBoxModel_->setCurrentEngineType(
    
    271
    +      HintingModeComboBoxModel::HintingEngineType_CFF, false);
    
    272
    +    hintingModeComboBox_->setCurrentIndex(currentCFFHintingMode_);
    
    273
    +  }
    
    274
    +  else if (engine_->currentFontType() == Engine::FontType_TrueType)
    
    275
    +  {
    
    276
    +    // TODO: tricky
    
    277
    +    hintingModeComboBoxModel_->setCurrentEngineType(
    
    278
    +      HintingModeComboBoxModel::HintingEngineType_TrueType, false);
    
    279
    +    hintingModeComboBox_->setCurrentIndex(currentTTInterpreterVersion_);
    
    280
    +  }
    
    281
    +  else
    
    282
    +  {
    
    283
    +    hintingModeLabel_->setEnabled(false);
    
    284
    +    hintingModeComboBox_->setEnabled(false);
    
    285
    +  }
    
    286
    +
    
    287
    +  checkHinting();
    
    288
    +
    
    289
    +  //engine_->reloadFont();
    
    290
    +  //auto hasColor = engine_->currentFontHasColorLayers();
    
    291
    +  //colorLayerCheckBox_->setEnabled(hasColor);
    
    292
    +  //if (!hasColor)
    
    293
    +  //  colorLayerCheckBox_->setChecked(false);
    
    294
    +  populatePalettes();
    
    295
    +  //mmgxPanel_->reloadFont();
    
    296
    +  blockSignals(blockState);
    
    297
    +
    
    298
    +  // Place this after `blockSignals` to let the signals emitted normally
    
    299
    +  //auto bmapOnly = engine_->currentFontBitmapOnly();
    
    300
    +  //embeddedBitmapCheckBox_->setEnabled(
    
    301
    +  //  !bmapOnly && engine_->currentFontHasEmbeddedBitmap());
    
    302
    +  //if (bmapOnly)
    
    303
    +  //  embeddedBitmapCheckBox_->setChecked(true);
    
    304
    +}
    
    305
    +
    
    306
    +
    
    307
    +void
    
    308
    +SettingPanel::applySettings()
    
    309
    +{
    
    310
    +  engine_->setLcdFilter(
    
    311
    +    static_cast<FT_LcdFilter>(lcdFilterComboboxModel_->indexToValue(
    
    312
    +      lcdFilterComboBox_->currentIndex())));
    
    313
    +
    
    314
    +  auto aaSettings = antiAliasingComboBoxModel_->indexToValue(
    
    315
    +    antiAliasingComboBox_->currentIndex());
    
    316
    +  engine_->setAntiAliasingTarget(aaSettings.loadFlag);
    
    317
    +  //engine_->setRenderMode(aaSettings.renderMode);
    
    318
    +
    
    319
    +  //engine_->setAntiAliasingEnabled(antiAliasingComboBox_->currentIndex()
    
    320
    +  //  != AntiAliasingComboBoxModel::AntiAliasing_None);
    
    321
    +  engine_->setHinting(hintingCheckBox_->isChecked());
    
    322
    +  engine_->setAutoHinting(autoHintingCheckBox_->isChecked());
    
    323
    +
    
    324
    +  if (debugMode_)
    
    325
    +  {
    
    326
    +    engine_->setHorizontalHinting(horizontalHintingCheckBox_->isChecked());
    
    327
    +    engine_->setVerticalHinting(verticalHintingCheckBox_->isChecked());
    
    328
    +    engine_->setBlueZoneHinting(blueZoneHintingCheckBox_->isChecked());
    
    329
    +    engine_->setShowSegments(segmentDrawingCheckBox_->isChecked());
    
    330
    +  }
    
    331
    +
    
    332
    +  engine_->setGamma(gammaSlider_->value() / 10.0);
    
    333
    +
    
    334
    +  //engine_->setEmbeddedBitmap(embeddedBitmapCheckBox_->isChecked());
    
    335
    +  //engine_->setPaletteIndex(paletteComboBox_->currentIndex());
    
    336
    +
    
    337
    +  //engine_->setUseColorLayer(colorLayerCheckBox_->isChecked());
    
    338
    +  //engine_->setLCDUsesBGR(aaSettings.isBGR);
    
    339
    +  //engine_->setLCDSubPixelPositioning(
    
    340
    +  //  antiAliasingComboBox_->currentIndex()
    
    341
    +  //    == AntiAliasingComboBoxModel::AntiAliasing_Light_SubPixel);
    
    342
    +
    
    343
    +  //engine_->renderingEngine()->setForeground(foregroundColor_.rgba());
    
    344
    +  //engine_->renderingEngine()->setBackground(backgroundColor_.rgba());
    
    345
    +  //mmgxPanel_->applySettings();
    
    346
    +}
    
    347
    +
    
    348
    +
    
    349
    +void
    
    350
    +SettingPanel::applyDelayedSettings()
    
    351
    +{
    
    352
    +  // This must not be combined into `applySettings`:
    
    353
    +  // those engine manipulations will reset the whole cache!!
    
    354
    +  // Therefore must only be called when the selection of the combo box actually
    
    355
    +  // changes a.k.a. QComboBox::activate.
    
    356
    +
    
    357
    +  int index = hintingModeComboBox_->currentIndex();
    
    358
    +
    
    359
    +  if (engine_->currentFontType() == Engine::FontType_CFF)
    
    360
    +  {
    
    361
    +    engine_->setCFFHintingMode(
    
    362
    +      hintingModeComboBoxModel_->indexToCFFMode(index));
    
    363
    +    if (index >= 0)
    
    364
    +      currentCFFHintingMode_ = index;
    
    365
    +  }
    
    366
    +  else if (engine_->currentFontType() == Engine::FontType_TrueType)
    
    367
    +  {
    
    368
    +    engine_->setTTInterpreterVersion(
    
    369
    +      hintingModeComboBoxModel_->indexToTTInterpreterVersion(index));
    
    370
    +    if (index >= 0)
    
    371
    +      currentTTInterpreterVersion_ = index;
    
    372
    +  }
    
    373
    +
    
    374
    +  //engine_->setStemDarkening(stemDarkeningCheckBox_->isChecked());
    
    375
    +}
    
    376
    +
    
    377
    +
    
    378
    +void
    
    379
    +SettingPanel::createLayout()
    
    380
    +{
    
    381
    +  hintingCheckBox_ = new QCheckBox(tr("Hinting"), this);
    
    382
    +
    
    383
    +  hintingModeLabel_ = new QLabel(tr("Hinting Mode"), this);
    
    384
    +  hintingModeLabel_->setAlignment(Qt::AlignRight);
    
    385
    +
    
    386
    +  hintingModeComboBoxModel_ = new HintingModeComboBoxModel(this);
    
    387
    +  hintingModeComboBox_ = new QComboBox(this);
    
    388
    +  hintingModeComboBox_->setModel(hintingModeComboBoxModel_);
    
    389
    +  hintingModeLabel_->setBuddy(hintingModeComboBox_);
    
    390
    +
    
    391
    +  autoHintingCheckBox_ = new QCheckBox(tr("Auto-Hinting"), this);
    
    392
    +  stemDarkeningCheckBox_ = new QCheckBox(tr("Stem Darkening"), this);
    
    393
    +
    
    394
    +  if (debugMode_)
    
    395
    +  {
    
    396
    +    horizontalHintingCheckBox_ = new QCheckBox(tr("Horizontal Hinting"), this);
    
    397
    +    verticalHintingCheckBox_ = new QCheckBox(tr("Vertical Hinting"), this);
    
    398
    +    blueZoneHintingCheckBox_ = new QCheckBox(tr("Blue-Zone Hinting"), this);
    
    399
    +    segmentDrawingCheckBox_ = new QCheckBox(tr("Segment Drawing"), this);
    
    400
    +  }
    
    401
    +  
    
    402
    +  embeddedBitmapCheckBox_ = new QCheckBox(tr("Enable Embedded Bitmap"), this);
    
    403
    +  colorLayerCheckBox_ = new QCheckBox(tr("Enable Color Layer"), this);
    
    404
    +
    
    405
    +  antiAliasingLabel_ = new QLabel(tr("Anti-Aliasing"), this);
    
    406
    +  antiAliasingLabel_->setAlignment(Qt::AlignRight);
    
    407
    +
    
    408
    +  antiAliasingComboBoxModel_ = new AntiAliasingComboBoxModel(this);
    
    409
    +  antiAliasingComboBox_ = new QComboBox(this);
    
    410
    +  antiAliasingComboBox_->setModel(antiAliasingComboBoxModel_);
    
    411
    +  antiAliasingLabel_->setBuddy(antiAliasingComboBox_);
    
    412
    +
    
    413
    +  lcdFilterLabel_ = new QLabel(tr("LCD Filter"), this);
    
    414
    +  lcdFilterLabel_->setAlignment(Qt::AlignRight);
    
    415
    +
    
    416
    +  lcdFilterComboboxModel_ = new LCDFilterComboBoxModel(this);
    
    417
    +  lcdFilterComboBox_ = new QComboBox(this);
    
    418
    +  lcdFilterComboBox_->setModel(lcdFilterComboboxModel_);
    
    419
    +  lcdFilterLabel_->setBuddy(lcdFilterComboBox_);
    
    420
    +
    
    421
    +  paletteLabel_ = new QLabel(tr("Palette: "), this);
    
    422
    +
    
    423
    +  paletteComboBox_ = new QComboBox(this);
    
    424
    +  paletteLabel_->setBuddy(paletteComboBox_);
    
    425
    +
    
    426
    +  gammaLabel_ = new QLabel(tr("Gamma"), this);
    
    427
    +  gammaLabel_->setAlignment(Qt::AlignRight);
    
    428
    +  gammaSlider_ = new QSlider(Qt::Horizontal, this);
    
    429
    +  gammaSlider_->setRange(3, 30); // in 1/10th
    
    430
    +  gammaSlider_->setTickPosition(QSlider::TicksBelow);
    
    431
    +  gammaSlider_->setTickInterval(5);
    
    432
    +  gammaSlider_->setPageStep(1);
    
    433
    +  gammaSlider_->setSingleStep(1);
    
    434
    +  gammaLabel_->setBuddy(gammaSlider_);
    
    435
    +  gammaValueLabel_ = new QLabel(this);
    
    436
    +
    
    437
    +  // TODO: MM/GX
    
    438
    +  mmgxPanel_ = new QWidget(this);
    
    439
    +
    
    440
    +  backgroundButton_ = new QPushButton(tr("Background"), this);
    
    441
    +  foregroundButton_ = new QPushButton(tr("Foreground"), this);
    
    442
    +
    
    443
    +  backgroundBlock_ = new QFrame(this);
    
    444
    +  backgroundBlock_->setFrameStyle(QFrame::Box);
    
    445
    +  backgroundBlock_->setLineWidth(1);
    
    446
    +  backgroundBlock_->setFixedWidth(18);
    
    447
    +
    
    448
    +  foregroundBlock_ = new QFrame(this);
    
    449
    +  foregroundBlock_->setFrameStyle(QFrame::Box);
    
    450
    +  foregroundBlock_->setLineWidth(1);
    
    451
    +  foregroundBlock_->setFixedWidth(18);
    
    452
    +
    
    453
    +  generalTab_ = new QWidget(this);
    
    454
    +
    
    455
    +  generalTab_->setSizePolicy(QSizePolicy::MinimumExpanding,
    
    456
    +                             QSizePolicy::MinimumExpanding);
    
    457
    +
    
    458
    +  tab_ = new QTabWidget(this);
    
    459
    +  tab_->setSizePolicy(QSizePolicy::MinimumExpanding,
    
    460
    +                      QSizePolicy::MinimumExpanding);
    
    461
    +
    
    462
    +  // Tooltips
    
    463
    +  hintingCheckBox_->setToolTip(tr("Enable hinting a.k.a. grid-fitting."));
    
    464
    +  hintingModeComboBox_->setToolTip(
    
    465
    +    tr("Modes not available for current font type will be disabled. No "
    
    466
    +       "effect when auto-hinting is enabled"));
    
    467
    +  autoHintingCheckBox_->setToolTip(tr("Enable FreeType Auto-Hinter."));
    
    468
    +  if (debugMode_)
    
    469
    +  {
    
    470
    +    horizontalHintingCheckBox_->setToolTip(tr("(auto-hinter debug option)"));
    
    471
    +    verticalHintingCheckBox_  ->setToolTip(tr("(auto-hinter debug option)"));
    
    472
    +    blueZoneHintingCheckBox_  ->setToolTip(tr("(auto-hinter debug option)"));
    
    473
    +    segmentDrawingCheckBox_   ->setToolTip(tr("(auto-hinter debug option)"));
    
    474
    +  }
    
    475
    +  antiAliasingComboBox_->setToolTip(tr("Select anti-aliasing mode."));
    
    476
    +  lcdFilterComboBox_->setToolTip(
    
    477
    +    tr("Select LCD filter (only valid when LCD AA is enabled)."));
    
    478
    +  embeddedBitmapCheckBox_->setToolTip(tr(
    
    479
    +    "Enable embedded bitmap strikes (force enabled for bitmap-only fonts)."));
    
    480
    +  stemDarkeningCheckBox_->setToolTip(
    
    481
    +    tr("Enable stem darkening (only valid for auto-hinter with gamma "
    
    482
    +       "correction enabled and with Light AA modes)."));
    
    483
    +  gammaSlider_->setToolTip("Gamma correction value.");
    
    484
    +  colorLayerCheckBox_->setToolTip(tr("Enable color layer rendering."));
    
    485
    +  paletteComboBox_->setToolTip(tr("Select color layer palette (only valid when "
    
    486
    +                                  "any palette exists in the font)."));
    
    487
    +  backgroundButton_->setToolTip(tr("Set canvas background color."));
    
    488
    +  foregroundButton_->setToolTip(tr("Set text color."));
    
    489
    +
    
    490
    +  // Layouting
    
    491
    +  if (debugMode_)
    
    492
    +  {
    
    493
    +    debugLayout_ = new QVBoxLayout;
    
    494
    +    debugLayout_->setContentsMargins(20, 0, 0, 0);
    
    495
    +    debugLayout_->addWidget(horizontalHintingCheckBox_);
    
    496
    +    debugLayout_->addWidget(verticalHintingCheckBox_);
    
    497
    +    debugLayout_->addWidget(blueZoneHintingCheckBox_);
    
    498
    +    debugLayout_->addWidget(segmentDrawingCheckBox_);
    
    499
    +  }
    
    500
    +
    
    501
    +  gammaLayout_ = new QHBoxLayout;
    
    502
    +  gammaLayout_->addWidget(gammaLabel_);
    
    503
    +  gammaLayout_->addWidget(gammaSlider_);
    
    504
    +  gammaLayout_->addWidget(gammaValueLabel_);
    
    505
    +
    
    506
    +  colorPickerLayout_ = new QHBoxLayout;
    
    507
    +  colorPickerLayout_->addWidget(backgroundBlock_);
    
    508
    +  colorPickerLayout_->addWidget(backgroundButton_, 1);
    
    509
    +  colorPickerLayout_->addWidget(foregroundButton_, 1);
    
    510
    +  colorPickerLayout_->addWidget(foregroundBlock_);
    
    511
    +
    
    512
    +  createLayoutNormal();
    
    513
    +  // TODO: Comparator mode.
    
    514
    +
    
    515
    +  mainLayout_ = new QVBoxLayout;
    
    516
    +  mainLayout_->addWidget(tab_);
    
    517
    +  setLayout(mainLayout_);
    
    518
    +  mainLayout_->setContentsMargins(0, 0, 0, 0);
    
    519
    +  setContentsMargins(0, 0, 0, 0);
    
    520
    +}
    
    521
    +
    
    522
    +
    
    523
    +void
    
    524
    +SettingPanel::createLayoutNormal()
    
    525
    +{
    
    526
    +  generalTabLayout_ = new QGridLayout;
    
    527
    +
    
    528
    +  gridLayout2ColAddWidget(generalTabLayout_, hintingCheckBox_);
    
    529
    +  gridLayout2ColAddWidget(generalTabLayout_, 
    
    530
    +                          hintingModeLabel_, hintingModeComboBox_);
    
    531
    +  gridLayout2ColAddWidget(generalTabLayout_, autoHintingCheckBox_);
    
    532
    +
    
    533
    +  if (debugMode_)
    
    534
    +    gridLayout2ColAddLayout(generalTabLayout_, debugLayout_);
    
    535
    +  
    
    536
    +  gridLayout2ColAddItem(generalTabLayout_,
    
    537
    +                        new QSpacerItem(0, 20, QSizePolicy::Minimum,
    
    538
    +                                        QSizePolicy::MinimumExpanding));
    
    539
    +
    
    540
    +  gridLayout2ColAddWidget(generalTabLayout_, 
    
    541
    +                          antiAliasingLabel_, antiAliasingComboBox_);
    
    542
    +  gridLayout2ColAddWidget(generalTabLayout_, 
    
    543
    +                          lcdFilterLabel_, lcdFilterComboBox_);
    
    544
    +  
    
    545
    +  gridLayout2ColAddItem(generalTabLayout_,
    
    546
    +                        new QSpacerItem(0, 20, QSizePolicy::Minimum,
    
    547
    +                                        QSizePolicy::MinimumExpanding));
    
    548
    +
    
    549
    +  gridLayout2ColAddLayout(generalTabLayout_, colorPickerLayout_);
    
    550
    +  gridLayout2ColAddLayout(generalTabLayout_, gammaLayout_);
    
    551
    +  gridLayout2ColAddWidget(generalTabLayout_, stemDarkeningCheckBox_);
    
    552
    +  gridLayout2ColAddWidget(generalTabLayout_, embeddedBitmapCheckBox_);
    
    553
    +  gridLayout2ColAddWidget(generalTabLayout_, colorLayerCheckBox_);
    
    554
    +  gridLayout2ColAddWidget(generalTabLayout_, 
    
    555
    +                          paletteLabel_, paletteComboBox_);
    
    556
    +  
    
    557
    +  gridLayout2ColAddItem(generalTabLayout_,
    
    558
    +                        new QSpacerItem(0, 20, QSizePolicy::Minimum,
    
    559
    +                                        QSizePolicy::MinimumExpanding));
    
    560
    +
    
    561
    +  generalTabLayout_->setColumnStretch(1, 1);
    
    562
    +  generalTab_->setLayout(generalTabLayout_);
    
    563
    +
    
    564
    +  tab_->addTab(generalTab_, tr("General"));
    
    565
    +  tab_->addTab(mmgxPanel_, tr("MM/GX"));
    
    566
    +
    
    567
    +  tab_->setTabToolTip(0, tr("General settings."));
    
    568
    +  tab_->setTabToolTip(1, tr("MM/GX axis parameters."));
    
    569
    +}
    
    570
    +
    
    571
    +
    
    572
    +void
    
    573
    +SettingPanel::createConnections()
    
    574
    +{
    
    575
    +  // use `qOverload` here to prevent ambiguity.
    
    576
    +  connect(hintingModeComboBox_, 
    
    577
    +          QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    578
    +          this, &SettingPanel::checkHintingMode);
    
    579
    +  connect(antiAliasingComboBox_,
    
    580
    +          QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    581
    +          this, &SettingPanel::checkAntiAliasing);
    
    582
    +  connect(lcdFilterComboBox_, 
    
    583
    +          QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    584
    +          this, &SettingPanel::repaintNeeded);
    
    585
    +  connect(paletteComboBox_,
    
    586
    +          QOverload<int>::of(&QComboBox::currentIndexChanged), 
    
    587
    +          this, &SettingPanel::repaintNeeded);
    
    588
    +
    
    589
    +  connect(gammaSlider_, &QSlider::valueChanged,
    
    590
    +          this, &SettingPanel::updateGamma);
    
    591
    +  
    
    592
    +  connect(hintingCheckBox_, &QCheckBox::clicked,
    
    593
    +          this, &SettingPanel::checkHinting);
    
    594
    +
    
    595
    +  if (debugMode_)
    
    596
    +  {
    
    597
    +    connect(horizontalHintingCheckBox_, &QCheckBox::clicked,
    
    598
    +            this, &SettingPanel::repaintNeeded);
    
    599
    +    connect(verticalHintingCheckBox_, &QCheckBox::clicked,
    
    600
    +            this, &SettingPanel::repaintNeeded);
    
    601
    +    connect(blueZoneHintingCheckBox_, &QCheckBox::clicked,
    
    602
    +            this, &SettingPanel::repaintNeeded);
    
    603
    +    connect(segmentDrawingCheckBox_, &QCheckBox::clicked,
    
    604
    +            this, &SettingPanel::repaintNeeded);
    
    605
    +  }
    
    606
    +
    
    607
    +  connect(autoHintingCheckBox_, &QCheckBox::clicked,
    
    608
    +          this, &SettingPanel::checkAutoHinting);
    
    609
    +  connect(embeddedBitmapCheckBox_, &QCheckBox::clicked,
    
    610
    +          this, &SettingPanel::fontReloadNeeded);
    
    611
    +  connect(stemDarkeningCheckBox_, &QCheckBox::clicked,
    
    612
    +          this, &SettingPanel::checkStemDarkening);
    
    613
    +  connect(colorLayerCheckBox_, &QCheckBox::clicked,
    
    614
    +          this, &SettingPanel::checkPalette);
    
    615
    +
    
    616
    +  connect(backgroundButton_, &QPushButton::clicked,
    
    617
    +          this, &SettingPanel::openBackgroundPicker);
    
    618
    +  connect(foregroundButton_, &QPushButton::clicked,
    
    619
    +          this, &SettingPanel::openForegroundPicker);
    
    620
    +}
    
    621
    +
    
    622
    +
    
    623
    +void
    
    624
    +SettingPanel::setDefaults()
    
    625
    +{
    
    626
    +  Engine::EngineDefaultValues& defaults = engine_->engineDefaults();
    
    627
    +
    
    628
    +  hintingModeComboBoxModel_->setSupportedModes(
    
    629
    +    { defaults.ttInterpreterVersionDefault,
    
    630
    +      defaults.ttInterpreterVersionOther,
    
    631
    +      defaults.ttInterpreterVersionOther1 },
    
    632
    +    { defaults.cffHintingEngineDefault, 
    
    633
    +      defaults.cffHintingEngineOther });
    
    634
    +
    
    635
    +  currentCFFHintingMode_
    
    636
    +    = hintingModeComboBoxModel_->cffModeToIndex(
    
    637
    +    defaults.cffHintingEngineDefault);
    
    638
    +  currentTTInterpreterVersion_
    
    639
    +    = hintingModeComboBoxModel_->ttInterpreterVersionToIndex(
    
    640
    +        defaults.ttInterpreterVersionDefault);
    
    641
    +
    
    642
    +  hintingCheckBox_->setChecked(true);
    
    643
    +
    
    644
    +  antiAliasingComboBox_->setCurrentIndex(
    
    645
    +    AntiAliasingComboBoxModel::AntiAliasing_Normal);
    
    646
    +  lcdFilterComboBox_->setCurrentIndex(
    
    647
    +    LCDFilterComboBoxModel::LCDFilter_Light);
    
    648
    +
    
    649
    +  if (debugMode_)
    
    650
    +  {
    
    651
    +    horizontalHintingCheckBox_->setChecked(true);
    
    652
    +    verticalHintingCheckBox_->setChecked(true);
    
    653
    +    blueZoneHintingCheckBox_->setChecked(true);
    
    654
    +    embeddedBitmapCheckBox_->setChecked(false);
    
    655
    +  }
    
    656
    +  
    
    657
    +  colorLayerCheckBox_->setChecked(true);
    
    658
    +  paletteComboBox_->setEnabled(false);
    
    659
    +
    
    660
    +  // These need to be set even in Comperator mode.
    
    661
    +  backgroundColor_ = Qt::white;
    
    662
    +  foregroundColor_ = Qt::black;
    
    663
    +  resetColorBlocks();
    
    664
    +
    
    665
    +  gammaSlider_->setValue(18); // 1.8
    
    666
    +  updateGamma();
    
    667
    +}
    
    668
    +
    
    669
    +
    
    670
    +// end of settingpanel.cpp

  • src/ftinspect/panels/settingpanel.hpp
    1
    +// settingpanel.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include "../engine/engine.hpp"
    
    8
    +#include "../models/customcomboboxmodels.hpp"
    
    9
    +
    
    10
    +#include <QWidget>
    
    11
    +#include <QTabWidget>
    
    12
    +#include <QLabel>
    
    13
    +#include <QComboBox>
    
    14
    +#include <QCheckBox>
    
    15
    +#include <QGridLayout>
    
    16
    +#include <QBoxLayout>
    
    17
    +#include <QPushButton>
    
    18
    +
    
    19
    +class SettingPanel
    
    20
    +: public QWidget
    
    21
    +{
    
    22
    +  Q_OBJECT
    
    23
    +public:
    
    24
    +  SettingPanel(QWidget* parent, Engine* engine);
    
    25
    +  ~SettingPanel() override = default;
    
    26
    +
    
    27
    +  void onFontChanged();
    
    28
    +  void applySettings();
    
    29
    +  /*
    
    30
    +   * When in comparator mode, this is needed to sync the hinting modes when
    
    31
    +   * reloading the font.
    
    32
    +   */
    
    33
    +  void applyDelayedSettings();
    
    34
    +
    
    35
    +  //////// Getters/Setters
    
    36
    +
    
    37
    +  int antiAliasingModeIndex();
    
    38
    +  bool kerningEnabled();
    
    39
    +  bool lsbRsbDeltaEnabled();
    
    40
    +
    
    41
    +signals:
    
    42
    +  void fontReloadNeeded();
    
    43
    +  void repaintNeeded();
    
    44
    +
    
    45
    +private:
    
    46
    +  Engine* engine_;
    
    47
    +
    
    48
    +  int currentCFFHintingMode_;
    
    49
    +  int currentTTInterpreterVersion_;
    
    50
    +  
    
    51
    +  bool debugMode_ = false;
    
    52
    +
    
    53
    +  QTabWidget* tab_;
    
    54
    +
    
    55
    +  QWidget* generalTab_;
    
    56
    +  QWidget* hintingRenderingTab_;
    
    57
    +  //SettingPanelMMGX* mmgxPanel_;
    
    58
    +  QWidget* mmgxPanel_;
    
    59
    +
    
    60
    +  QLabel* gammaLabel_;
    
    61
    +  QLabel* gammaValueLabel_;
    
    62
    +  QLabel* antiAliasingLabel_;
    
    63
    +  QLabel* hintingModeLabel_;
    
    64
    +  QLabel* lcdFilterLabel_;
    
    65
    +  QLabel* paletteLabel_;
    
    66
    +
    
    67
    +  QCheckBox* hintingCheckBox_;
    
    68
    +  QCheckBox* horizontalHintingCheckBox_;
    
    69
    +  QCheckBox* verticalHintingCheckBox_;
    
    70
    +  QCheckBox* blueZoneHintingCheckBox_;
    
    71
    +  QCheckBox* segmentDrawingCheckBox_;
    
    72
    +  QCheckBox* autoHintingCheckBox_;
    
    73
    +  QCheckBox* stemDarkeningCheckBox_;
    
    74
    +  QCheckBox* embeddedBitmapCheckBox_;
    
    75
    +  QCheckBox* colorLayerCheckBox_;
    
    76
    +  QCheckBox* kerningCheckBox_;
    
    77
    +  QCheckBox* lsbRsbDeltaCheckBox_;
    
    78
    +
    
    79
    +  AntiAliasingComboBoxModel* antiAliasingComboBoxModel_;
    
    80
    +  HintingModeComboBoxModel* hintingModeComboBoxModel_;
    
    81
    +  LCDFilterComboBoxModel* lcdFilterComboboxModel_;
    
    82
    +
    
    83
    +  QComboBox* hintingModeComboBox_;
    
    84
    +  QComboBox* antiAliasingComboBox_;
    
    85
    +  QComboBox* lcdFilterComboBox_;
    
    86
    +  QComboBox* paletteComboBox_;
    
    87
    +
    
    88
    +  QSlider* gammaSlider_;
    
    89
    +
    
    90
    +  QPushButton* backgroundButton_;
    
    91
    +  QPushButton* foregroundButton_;
    
    92
    +  QFrame* backgroundBlock_;
    
    93
    +  QFrame* foregroundBlock_;
    
    94
    +
    
    95
    +  QVBoxLayout* mainLayout_;
    
    96
    +  QGridLayout* generalTabLayout_;
    
    97
    +  QGridLayout* hintingRenderingTabLayout_;
    
    98
    +  QVBoxLayout* debugLayout_;
    
    99
    +  QHBoxLayout* gammaLayout_;
    
    100
    +  QHBoxLayout* colorPickerLayout_;
    
    101
    +
    
    102
    +  QColor backgroundColor_;
    
    103
    +  QColor foregroundColor_;
    
    104
    +
    
    105
    +  //////// Initializing funcs
    
    106
    +
    
    107
    +  void createConnections();
    
    108
    +  void createLayout();
    
    109
    +  void createLayoutNormal();
    
    110
    +  void setDefaults();
    
    111
    +
    
    112
    +  //////// Other funcs
    
    113
    +
    
    114
    +  void populatePalettes();
    
    115
    +
    
    116
    +  void checkAllSettings();
    
    117
    +  void checkHinting();
    
    118
    +  void checkHintingMode();
    
    119
    +  void checkAutoHinting();
    
    120
    +  void checkAntiAliasing();
    
    121
    +  void checkPalette();
    
    122
    +  void checkStemDarkening();
    
    123
    +
    
    124
    +  void openBackgroundPicker();
    
    125
    +  void openForegroundPicker();
    
    126
    +  void updateGamma();
    
    127
    +  void resetColorBlocks();
    
    128
    +};
    
    129
    +
    
    130
    +
    
    131
    +// end of settingpanel.hpp

  • src/ftinspect/panels/singular.cpp
    1
    +// singular.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "singular.hpp"
    
    6
    +
    
    7
    +#include <QSizePolicy>
    
    8
    +#include <QToolTip>
    
    9
    +#include <QWheelEvent>
    
    10
    +
    
    11
    +
    
    12
    +SingularTab::SingularTab(QWidget* parent, Engine* engine)
    
    13
    +: QWidget(parent), engine_(engine),
    
    14
    +  graphicsDefault_(GraphicsDefault::deafultInstance())
    
    15
    +{
    
    16
    +  createLayout();
    
    17
    +  createConnections();
    
    18
    +
    
    19
    +  currentGlyphIndex_ = 0;
    
    20
    +  setDefaults();
    
    21
    +  checkShowPoints();
    
    22
    +}
    
    23
    +
    
    24
    +
    
    25
    +SingularTab::~SingularTab()
    
    26
    +{
    
    27
    +  delete gridItem_;
    
    28
    +  gridItem_ = NULL;
    
    29
    +}
    
    30
    +
    
    31
    +
    
    32
    +void
    
    33
    +SingularTab::setGlyphIndex(int index)
    
    34
    +{
    
    35
    +  // only adjust current glyph index if we have a valid font
    
    36
    +  if (currentGlyphCount_ <= 0)
    
    37
    +    return;
    
    38
    +
    
    39
    +  currentGlyphIndex_ = qBound(0, index, currentGlyphCount_ - 1);
    
    40
    +
    
    41
    +  QString upperHex = QString::number(currentGlyphIndex_, 16).toUpper();
    
    42
    +  glyphIndexLabel_->setText(
    
    43
    +      QString("%1 (0x%2)").arg(currentGlyphIndex_).arg(upperHex));
    
    44
    +  glyphNameLabel_->setText(engine_->glyphName(currentGlyphIndex_));
    
    45
    +
    
    46
    +  drawGlyph();
    
    47
    +}
    
    48
    +
    
    49
    +
    
    50
    +void
    
    51
    +SingularTab::drawGlyph()
    
    52
    +{
    
    53
    +  // the call to `engine->loadOutline' updates FreeType's load flags
    
    54
    +
    
    55
    +  if (!engine_)
    
    56
    +    return;
    
    57
    +
    
    58
    +  if (currentGlyphBitmapItem_)
    
    59
    +  {
    
    60
    +    glyphScene_->removeItem(currentGlyphBitmapItem_);
    
    61
    +    delete currentGlyphBitmapItem_;
    
    62
    +
    
    63
    +    currentGlyphBitmapItem_ = NULL;
    
    64
    +  }
    
    65
    +
    
    66
    +  if (currentGlyphOutlineItem_)
    
    67
    +  {
    
    68
    +    glyphScene_->removeItem(currentGlyphOutlineItem_);
    
    69
    +    delete currentGlyphOutlineItem_;
    
    70
    +
    
    71
    +    currentGlyphOutlineItem_ = NULL;
    
    72
    +  }
    
    73
    +
    
    74
    +  if (currentGlyphPointsItem_)
    
    75
    +  {
    
    76
    +    glyphScene_->removeItem(currentGlyphPointsItem_);
    
    77
    +    delete currentGlyphPointsItem_;
    
    78
    +
    
    79
    +    currentGlyphPointsItem_ = NULL;
    
    80
    +  }
    
    81
    +
    
    82
    +  if (currentGlyphPointNumbersItem_)
    
    83
    +  {
    
    84
    +    glyphScene_->removeItem(currentGlyphPointNumbersItem_);
    
    85
    +    delete currentGlyphPointNumbersItem_;
    
    86
    +
    
    87
    +    currentGlyphPointNumbersItem_ = NULL;
    
    88
    +  }
    
    89
    +
    
    90
    +  // TODO refactor engine.
    
    91
    +  //glyphView_->setBackgroundBrush(
    
    92
    +  //  QColor(engine_->renderingEngine()->background()));
    
    93
    +
    
    94
    +  applySettings();
    
    95
    +  FT_Glyph glyph = NULL; // TODO: refactor engine!
    
    96
    +  //FT_Glyph glyph = engine_->loadGlyph(currentGlyphIndex_);
    
    97
    +  if (glyph)
    
    98
    +  {
    
    99
    +    if (showBitmapCheckBox_->isChecked())
    
    100
    +    {
    
    101
    +      currentGlyphBitmapItem_
    
    102
    +        = new GlyphBitmap(currentGlyphIndex_, 
    
    103
    +                          glyph,
    
    104
    +                          engine_);
    
    105
    +      currentGlyphBitmapItem_->setZValue(-1);
    
    106
    +      glyphScene_->addItem(currentGlyphBitmapItem_);
    
    107
    +    }
    
    108
    +
    
    109
    +    if (showOutlinesCheckBox_->isChecked())
    
    110
    +    {
    
    111
    +      currentGlyphOutlineItem_ = new GlyphOutline(graphicsDefault_->outlinePen, 
    
    112
    +                                                  glyph);
    
    113
    +      currentGlyphOutlineItem_->setZValue(1);
    
    114
    +      glyphScene_->addItem(currentGlyphOutlineItem_);
    
    115
    +    }
    
    116
    +
    
    117
    +    if (showPointsCheckBox_->isChecked())
    
    118
    +    {
    
    119
    +      currentGlyphPointsItem_ = new GlyphPoints(graphicsDefault_->onPen,
    
    120
    +                                                graphicsDefault_->offPen,
    
    121
    +                                                glyph);
    
    122
    +      currentGlyphPointsItem_->setZValue(1);
    
    123
    +      glyphScene_->addItem(currentGlyphPointsItem_);
    
    124
    +
    
    125
    +      if (showPointNumbersCheckBox_->isChecked())
    
    126
    +      {
    
    127
    +        currentGlyphPointNumbersItem_
    
    128
    +          = new GlyphPointNumbers(graphicsDefault_->onPen,
    
    129
    +                                  graphicsDefault_->offPen,
    
    130
    +                                  glyph);
    
    131
    +        currentGlyphPointNumbersItem_->setZValue(1);
    
    132
    +        glyphScene_->addItem(currentGlyphPointNumbersItem_);
    
    133
    +      }
    
    134
    +    }
    
    135
    +  }
    
    136
    +
    
    137
    +  glyphScene_->update();
    
    138
    +}
    
    139
    +
    
    140
    +
    
    141
    +void
    
    142
    +SingularTab::checkShowPoints()
    
    143
    +{
    
    144
    +  if (showPointsCheckBox_->isChecked())
    
    145
    +    showPointNumbersCheckBox_->setEnabled(true);
    
    146
    +  else
    
    147
    +    showPointNumbersCheckBox_->setEnabled(false);
    
    148
    +  drawGlyph();
    
    149
    +}
    
    150
    +
    
    151
    +
    
    152
    +void
    
    153
    +SingularTab::zoom()
    
    154
    +{
    
    155
    +  int scale = static_cast<int>(sizeSelector_->zoomFactor());
    
    156
    +
    
    157
    +  QTransform transform;
    
    158
    +  transform.scale(scale, scale);
    
    159
    +
    
    160
    +  // we want horizontal and vertical 1px lines displayed with full pixels;
    
    161
    +  // we thus have to shift the coordinate system accordingly, using a value
    
    162
    +  // that represents 0.5px (i.e., half the 1px line width) after the scaling
    
    163
    +  qreal shift = 0.5 / scale;
    
    164
    +  transform.translate(shift, shift);
    
    165
    +
    
    166
    +  glyphView_->setTransform(transform);
    
    167
    +  updateGrid();
    
    168
    +}
    
    169
    +
    
    170
    +
    
    171
    +void
    
    172
    +SingularTab::backToCenter()
    
    173
    +{
    
    174
    +  glyphView_->centerOn(0, 0);
    
    175
    +  if (currentGlyphBitmapItem_)
    
    176
    +    glyphView_->ensureVisible(currentGlyphBitmapItem_);
    
    177
    +  else if (currentGlyphPointsItem_)
    
    178
    +    glyphView_->ensureVisible(currentGlyphPointsItem_);
    
    179
    +
    
    180
    +  updateGrid();
    
    181
    +}
    
    182
    +
    
    183
    +
    
    184
    +void
    
    185
    +SingularTab::updateGrid()
    
    186
    +{
    
    187
    +  if (gridItem_)
    
    188
    +    gridItem_->updateRect();
    
    189
    +}
    
    190
    +
    
    191
    +
    
    192
    +void
    
    193
    +SingularTab::wheelZoom(QWheelEvent* event)
    
    194
    +{
    
    195
    +  int numSteps = event->angleDelta().y() / 120;
    
    196
    +  sizeSelector_->handleWheelZoomBySteps(numSteps);
    
    197
    +  // TODO: Zoom relative to viewport left-bottom?
    
    198
    +}
    
    199
    +
    
    200
    +
    
    201
    +void
    
    202
    +SingularTab::wheelResize(QWheelEvent* event)
    
    203
    +{
    
    204
    +  sizeSelector_->handleWheelResizeFromGrid(event);
    
    205
    +}
    
    206
    +
    
    207
    +
    
    208
    +void
    
    209
    +SingularTab::setGridVisible()
    
    210
    +{
    
    211
    +  gridItem_->setShowGrid(showGridCheckBox_->isChecked(),
    
    212
    +                         showAuxLinesCheckBox_->isChecked());
    
    213
    +}
    
    214
    +
    
    215
    +
    
    216
    +void
    
    217
    +SingularTab::showToolTip()
    
    218
    +{
    
    219
    +  QToolTip::showText(mapToGlobal(helpButton_->pos()),
    
    220
    +                     tr("Scroll: Grid Up/Down\n"
    
    221
    +                        "Alt + Scroll: Grid Left/Right\n"
    
    222
    +                        "Ctrl + Scroll: Adjust Zoom (Relative to cursor)\n"
    
    223
    +                        "Shift + Scroll: Adjust Font Size\n"
    
    224
    +                        "Shift + Plus/Minus: Adjust Font Size\n"
    
    225
    +                        "Shift + 0: Reset Font Size to Default"),
    
    226
    +                     helpButton_);
    
    227
    +}
    
    228
    +
    
    229
    +
    
    230
    +bool
    
    231
    +SingularTab::eventFilter(QObject* watched,
    
    232
    +                         QEvent* event)
    
    233
    +{
    
    234
    +  if (event->type() == QEvent::KeyPress)
    
    235
    +  {
    
    236
    +    auto keyEvent = dynamic_cast<QKeyEvent*>(event);
    
    237
    +    if (sizeSelector_->handleKeyEvent(keyEvent))
    
    238
    +      return true;
    
    239
    +  }
    
    240
    +  return false;
    
    241
    +}
    
    242
    +
    
    243
    +
    
    244
    +void
    
    245
    +SingularTab::resizeEvent(QResizeEvent* event)
    
    246
    +{
    
    247
    +  QWidget::resizeEvent(event);
    
    248
    +
    
    249
    +  // Tricky part: when loading, this method will be called twice. Only at the
    
    250
    +  // second time the initial layouting is done, thus the result of `centerOn`
    
    251
    +  // can be valid.
    
    252
    +  // We want to only center the midpoint of the size when the program starts up
    
    253
    +  // so we use a counter to track the status.
    
    254
    +  if (initialPositionSetCount_ <= 0)
    
    255
    +    return;
    
    256
    +  initialPositionSetCount_--;
    
    257
    +
    
    258
    +  // The code below mainly:
    
    259
    +  // 1. Center the grid on the the center point of the ppem x ppem bbox.
    
    260
    +  // 2. Adjust the viewport zoom to fit the ppem x ppem bbox
    
    261
    +  updateGeometry();
    
    262
    +  auto size = sizeSelector_->selectedSize();
    
    263
    +  auto unit = sizeSelector_->selectedUnit();
    
    264
    +  if (unit == FontSizeSelector::Units_pt)
    
    265
    +  {
    
    266
    +    sizeSelector_->applyToEngine(engine_);
    
    267
    +    auto dpi = engine_->dpi();
    
    268
    +    size = size * dpi / 72.0;
    
    269
    +  }
    
    270
    +  glyphView_->centerOn(size / 2, -size / 2);
    
    271
    +
    
    272
    +  auto viewSize = glyphView_->size();
    
    273
    +  auto minViewSide = std::min(viewSize.height(), viewSize.width());
    
    274
    +  sizeSelector_->setZoomFactor(static_cast<int>(minViewSide / size * 0.7));
    
    275
    +}
    
    276
    +
    
    277
    +
    
    278
    +void
    
    279
    +SingularTab::createLayout()
    
    280
    +{
    
    281
    +  glyphScene_ = new QGraphicsScene(this);
    
    282
    +
    
    283
    +  currentGlyphBitmapItem_ = NULL;
    
    284
    +  currentGlyphOutlineItem_ = NULL;
    
    285
    +  currentGlyphPointsItem_ = NULL;
    
    286
    +  currentGlyphPointNumbersItem_ = NULL;
    
    287
    +
    
    288
    +  glyphView_ = new QGraphicsViewx(this);
    
    289
    +  glyphView_->setRenderHint(QPainter::Antialiasing, true);
    
    290
    +  glyphView_->setAcceptDrops(false);
    
    291
    +  glyphView_->setDragMode(QGraphicsView::ScrollHandDrag);
    
    292
    +  glyphView_->setOptimizationFlags(QGraphicsView::DontSavePainterState);
    
    293
    +  glyphView_->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    
    294
    +  glyphView_->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    
    295
    +  glyphView_->setScene(glyphScene_);
    
    296
    +  glyphView_->setBackgroundBrush(Qt::white);
    
    297
    +
    
    298
    +  gridItem_ = new Grid(glyphView_);
    
    299
    +  glyphScene_->addItem(gridItem_);
    
    300
    +
    
    301
    +  // Don't use QGraphicsTextItem: We want this hint to be anchored at the
    
    302
    +  // top-left corner.
    
    303
    +  auto overlayFont = font();
    
    304
    +  overlayFont.setPixelSize(24);
    
    305
    +
    
    306
    +  glyphIndexLabel_ = new QLabel(glyphView_);
    
    307
    +  glyphNameLabel_ = new QLabel(glyphView_);
    
    308
    +  glyphIndexLabel_->setFont(overlayFont);
    
    309
    +  glyphNameLabel_->setFont(overlayFont);
    
    310
    +  glyphIndexLabel_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    
    311
    +  glyphNameLabel_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    
    312
    +  glyphIndexLabel_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    313
    +  glyphNameLabel_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    314
    +
    
    315
    +  glyphIndexLabel_->setStyleSheet("QLabel { color : black; }");
    
    316
    +  glyphNameLabel_->setStyleSheet("QLabel { color : black; }");
    
    317
    +
    
    318
    +  indexSelector_ = new GlyphIndexSelector(this);
    
    319
    +  indexSelector_->setSingleMode(true);
    
    320
    +
    
    321
    +  sizeSelector_ = new FontSizeSelector(this, false, false);
    
    322
    +
    
    323
    +  centerGridButton_ = new QPushButton("Go Back to Grid Center", this);
    
    324
    +  helpButton_ = new QPushButton("?", this);
    
    325
    +  helpButton_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    
    326
    +
    
    327
    +  showBitmapCheckBox_ = new QCheckBox(tr("Show Bitmap"), this);
    
    328
    +  showPointsCheckBox_ = new QCheckBox(tr("Show Points"), this);
    
    329
    +  showPointNumbersCheckBox_ = new QCheckBox(tr("Show Point Numbers"), this);
    
    330
    +  showOutlinesCheckBox_ = new QCheckBox(tr("Show Outlines"), this);
    
    331
    +  showGridCheckBox_ = new QCheckBox(tr("Show Grid"), this);
    
    332
    +  showAuxLinesCheckBox_ = new QCheckBox(tr("Show Aux. Lines"), this);
    
    333
    +
    
    334
    +  // Tooltips
    
    335
    +  centerGridButton_->setToolTip(tr(
    
    336
    +    "Move the viewport so the origin point is at the center of the view."));
    
    337
    +  showBitmapCheckBox_->setToolTip(tr("Show glyph bitmap."));
    
    338
    +  showPointsCheckBox_->setToolTip(
    
    339
    +    tr("Show control points (only valid when the glyph is an outline glyph)."));
    
    340
    +  showPointNumbersCheckBox_->setToolTip(
    
    341
    +    tr("Show point numbers (only available when points are shown)."));
    
    342
    +  showOutlinesCheckBox_->setToolTip(tr("Show (vector) outline (only valid when "
    
    343
    +                                       "the glyph is an outline glyph)."));
    
    344
    +  showGridCheckBox_->setToolTip(tr("Show grid lines (x axis: baseline)."));
    
    345
    +  showBitmapCheckBox_->setToolTip(
    
    346
    +    tr("Show auxiliary lines (blue: y-advance; red: ascender/descender)."));
    
    347
    +  helpButton_->setToolTip(tr("View scroll help"));
    
    348
    +
    
    349
    +  // Layouting
    
    350
    +  indexHelpLayout_ = new QHBoxLayout;
    
    351
    +  indexHelpLayout_->addWidget(indexSelector_, 1);
    
    352
    +  indexHelpLayout_->addWidget(helpButton_);
    
    353
    +
    
    354
    +  sizeLayout_ = new QHBoxLayout;
    
    355
    +  sizeLayout_->addStretch(2);
    
    356
    +  sizeLayout_->addWidget(sizeSelector_, 4);
    
    357
    +  sizeLayout_->addStretch(1);
    
    358
    +  sizeLayout_->addWidget(centerGridButton_);
    
    359
    +  sizeLayout_->addStretch(2);
    
    360
    +
    
    361
    +  checkBoxesLayout_ = new QHBoxLayout;
    
    362
    +  checkBoxesLayout_->setSpacing(10);
    
    363
    +  checkBoxesLayout_->addWidget(showBitmapCheckBox_);
    
    364
    +  checkBoxesLayout_->addWidget(showPointsCheckBox_);
    
    365
    +  checkBoxesLayout_->addWidget(showPointNumbersCheckBox_);
    
    366
    +  checkBoxesLayout_->addWidget(showOutlinesCheckBox_);
    
    367
    +  checkBoxesLayout_->addWidget(showGridCheckBox_);
    
    368
    +  checkBoxesLayout_->addWidget(showAuxLinesCheckBox_);
    
    369
    +
    
    370
    +  glyphOverlayIndexLayout_ = new QHBoxLayout;
    
    371
    +  glyphOverlayIndexLayout_->addWidget(glyphIndexLabel_);
    
    372
    +  glyphOverlayIndexLayout_->addWidget(glyphNameLabel_);
    
    373
    +  glyphOverlayLayout_ = new QGridLayout; // use a grid layout to align
    
    374
    +  glyphOverlayLayout_->addLayout(glyphOverlayIndexLayout_, 0, 1,
    
    375
    +                                 Qt::AlignTop | Qt::AlignRight);
    
    376
    +  glyphView_->setLayout(glyphOverlayLayout_);
    
    377
    +
    
    378
    +  mainLayout_ = new QVBoxLayout;
    
    379
    +  mainLayout_->addWidget(glyphView_);
    
    380
    +  mainLayout_->addLayout(indexHelpLayout_);
    
    381
    +  mainLayout_->addSpacing(10);
    
    382
    +  mainLayout_->addLayout(sizeLayout_);
    
    383
    +  mainLayout_->addLayout(checkBoxesLayout_);
    
    384
    +  mainLayout_->addSpacing(10);
    
    385
    +
    
    386
    +  setLayout(mainLayout_);
    
    387
    +}
    
    388
    +
    
    389
    +
    
    390
    +void
    
    391
    +SingularTab::createConnections()
    
    392
    +{
    
    393
    +  connect(sizeSelector_, &FontSizeSelector::valueChanged,
    
    394
    +          this, &SingularTab::repaintGlyph);
    
    395
    +  connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged, 
    
    396
    +          this, &SingularTab::setGlyphIndex);
    
    397
    +  
    
    398
    +  connect(glyphView_, &QGraphicsViewx::shiftWheelEvent, 
    
    399
    +          this, &SingularTab::wheelResize);
    
    400
    +  connect(glyphView_, &QGraphicsViewx::ctrlWheelEvent, 
    
    401
    +          this, &SingularTab::wheelZoom);
    
    402
    +  // Use `updateGrid` to support infinite panning.
    
    403
    +  connect(glyphView_->horizontalScrollBar(), &QScrollBar::valueChanged,
    
    404
    +          this, &SingularTab::updateGrid);
    
    405
    +  connect(glyphView_->verticalScrollBar(), &QScrollBar::valueChanged, 
    
    406
    +          this, &SingularTab::updateGrid);
    
    407
    +
    
    408
    +  connect(centerGridButton_, &QPushButton::clicked,
    
    409
    +          this, &SingularTab::backToCenter);
    
    410
    +  connect(helpButton_, &QPushButton::clicked,
    
    411
    +          this, &SingularTab::showToolTip);
    
    412
    +
    
    413
    +  connect(showBitmapCheckBox_, &QCheckBox::clicked,
    
    414
    +          this, &SingularTab::drawGlyph);
    
    415
    +  connect(showPointsCheckBox_, &QCheckBox::clicked, 
    
    416
    +          this, &SingularTab::checkShowPoints);
    
    417
    +  connect(showPointNumbersCheckBox_, &QCheckBox::clicked,
    
    418
    +          this, &SingularTab::drawGlyph);
    
    419
    +  connect(showOutlinesCheckBox_, &QCheckBox::clicked,
    
    420
    +          this, &SingularTab::drawGlyph);
    
    421
    +  connect(showGridCheckBox_, &QCheckBox::clicked,
    
    422
    +          this, &SingularTab::setGridVisible);
    
    423
    +  connect(showAuxLinesCheckBox_, &QCheckBox::clicked,
    
    424
    +          this, &SingularTab::setGridVisible);
    
    425
    +
    
    426
    +  sizeSelector_->installEventFilterForWidget(glyphView_);
    
    427
    +  sizeSelector_->installEventFilterForWidget(this);
    
    428
    +}
    
    429
    +
    
    430
    +
    
    431
    +void
    
    432
    +SingularTab::repaintGlyph()
    
    433
    +{
    
    434
    +  zoom();
    
    435
    +  drawGlyph();
    
    436
    +}
    
    437
    +
    
    438
    +
    
    439
    +void
    
    440
    +SingularTab::reloadFont()
    
    441
    +{
    
    442
    +  currentGlyphCount_ = engine_->currentFontNumberOfGlyphs();
    
    443
    +  indexSelector_->setMinMax(0, currentGlyphCount_);
    
    444
    +  {
    
    445
    +    QSignalBlocker blocker(sizeSelector_);
    
    446
    +    sizeSelector_->reloadFromFont(engine_);
    
    447
    +  }
    
    448
    +  drawGlyph();
    
    449
    +}
    
    450
    +
    
    451
    +
    
    452
    +void
    
    453
    +SingularTab::setCurrentGlyphAndSize(int glyphIndex,
    
    454
    +                                    double sizePoint)
    
    455
    +{
    
    456
    +  if (sizePoint >= 0)
    
    457
    +    sizeSelector_->setSizePoint(sizePoint);
    
    458
    +  indexSelector_->setCurrentIndex(glyphIndex); // this will auto trigger update
    
    459
    +}
    
    460
    +
    
    461
    +
    
    462
    +int
    
    463
    +SingularTab::currentGlyph()
    
    464
    +{
    
    465
    +  return indexSelector_->currentIndex();
    
    466
    +}
    
    467
    +
    
    468
    +
    
    469
    +void
    
    470
    +SingularTab::applySettings()
    
    471
    +{
    
    472
    +  sizeSelector_->applyToEngine(engine_);
    
    473
    +}
    
    474
    +
    
    475
    +
    
    476
    +void
    
    477
    +SingularTab::setDefaults()
    
    478
    +{
    
    479
    +  currentGlyphIndex_ = 0;
    
    480
    +
    
    481
    +  showBitmapCheckBox_->setChecked(true);
    
    482
    +  showOutlinesCheckBox_->setChecked(true);
    
    483
    +  showGridCheckBox_->setChecked(true);
    
    484
    +  showAuxLinesCheckBox_->setChecked(true);
    
    485
    +  gridItem_->setShowGrid(true, true);
    
    486
    +
    
    487
    +  indexSelector_->setCurrentIndex(indexSelector_->currentIndex(), true);
    
    488
    +  zoom();
    
    489
    +}
    
    490
    +
    
    491
    +
    
    492
    +// end of singular.cpp

  • src/ftinspect/panels/singular.hpp
    1
    +// singular.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include "abstracttab.hpp"
    
    8
    +#include "../widgets/customwidgets.hpp"
    
    9
    +#include "../widgets/glyphindexselector.hpp"
    
    10
    +#include "../widgets/fontsizeselector.hpp"
    
    11
    +#include "../glyphcomponents/glyphbitmap.hpp"
    
    12
    +#include "../glyphcomponents/glyphoutline.hpp"
    
    13
    +#include "../glyphcomponents/glyphpointnumbers.hpp"
    
    14
    +#include "../glyphcomponents/glyphpoints.hpp"
    
    15
    +#include "../glyphcomponents/grid.hpp"
    
    16
    +#include "../glyphcomponents/graphicsdefault.hpp"
    
    17
    +#include "../engine/engine.hpp"
    
    18
    +#include "../models/customcomboboxmodels.hpp"
    
    19
    +
    
    20
    +#include <QWidget>
    
    21
    +#include <QPushButton>
    
    22
    +#include <QSpinBox>
    
    23
    +#include <QGraphicsScene>
    
    24
    +#include <QGraphicsView>
    
    25
    +#include <QScrollBar>
    
    26
    +#include <QLabel>
    
    27
    +#include <QComboBox>
    
    28
    +#include <QPen>
    
    29
    +#include <QCheckBox>
    
    30
    +#include <QVector>
    
    31
    +#include <QGridLayout>
    
    32
    +#include <QBoxLayout>
    
    33
    +
    
    34
    +class SingularTab
    
    35
    +: public QWidget, public AbstractTab
    
    36
    +{
    
    37
    +  Q_OBJECT
    
    38
    +public:
    
    39
    +  SingularTab(QWidget* parent, Engine* engine);
    
    40
    +  ~SingularTab() override;
    
    41
    +
    
    42
    +  void repaintGlyph() override;
    
    43
    +  void reloadFont() override;
    
    44
    +  // when sizePoint <= 0, the size remains unchanged.
    
    45
    +  void setCurrentGlyphAndSize(int glyphIndex, double sizePoint);
    
    46
    +  int currentGlyph();
    
    47
    +
    
    48
    +private slots:
    
    49
    +  void setGlyphIndex(int);
    
    50
    +  void drawGlyph();
    
    51
    +  
    
    52
    +  void checkShowPoints();
    
    53
    +
    
    54
    +  void zoom();
    
    55
    +  void backToCenter();
    
    56
    +  void wheelZoom(QWheelEvent* event);
    
    57
    +  void wheelResize(QWheelEvent* event);
    
    58
    +  void setGridVisible();
    
    59
    +  void showToolTip();
    
    60
    +
    
    61
    +protected:
    
    62
    +  bool eventFilter(QObject* watched, QEvent* event) override;
    
    63
    +  void resizeEvent(QResizeEvent* event) override;
    
    64
    +
    
    65
    +private:
    
    66
    +  int currentGlyphIndex_;
    
    67
    +  int currentGlyphCount_;
    
    68
    +
    
    69
    +  Engine* engine_;
    
    70
    +
    
    71
    +  QGraphicsScene* glyphScene_;
    
    72
    +  QGraphicsViewx* glyphView_;
    
    73
    +
    
    74
    +  GlyphOutline* currentGlyphOutlineItem_;
    
    75
    +  GlyphPoints* currentGlyphPointsItem_;
    
    76
    +  GlyphPointNumbers* currentGlyphPointNumbersItem_;
    
    77
    +  GlyphBitmap* currentGlyphBitmapItem_;
    
    78
    +  Grid* gridItem_ = NULL;
    
    79
    +
    
    80
    +  GlyphIndexSelector* indexSelector_;
    
    81
    +  FontSizeSelector* sizeSelector_;
    
    82
    +  QPushButton* centerGridButton_;
    
    83
    +  QPushButton* helpButton_;
    
    84
    +
    
    85
    +  QLabel* glyphIndexLabel_;
    
    86
    +  QLabel* glyphNameLabel_;
    
    87
    +
    
    88
    +  QCheckBox* showBitmapCheckBox_;
    
    89
    +  QCheckBox* showOutlinesCheckBox_;
    
    90
    +  QCheckBox* showPointNumbersCheckBox_;
    
    91
    +  QCheckBox* showPointsCheckBox_;
    
    92
    +  QCheckBox* showGridCheckBox_;
    
    93
    +  QCheckBox* showAuxLinesCheckBox_;
    
    94
    +
    
    95
    +  QVBoxLayout* mainLayout_;
    
    96
    +  QHBoxLayout* checkBoxesLayout_;
    
    97
    +  QHBoxLayout* indexHelpLayout_;
    
    98
    +  QHBoxLayout* sizeLayout_;
    
    99
    +  QGridLayout* glyphOverlayLayout_;
    
    100
    +  QHBoxLayout* glyphOverlayIndexLayout_;
    
    101
    +
    
    102
    +  GraphicsDefault* graphicsDefault_;
    
    103
    +
    
    104
    +  int initialPositionSetCount_ = 2; // see `resizeEvent`
    
    105
    +
    
    106
    +  void createLayout();
    
    107
    +  void createConnections();
    
    108
    +  
    
    109
    +  void updateGrid();
    
    110
    +  void applySettings();
    
    111
    +  void setDefaults();
    
    112
    +};
    
    113
    +
    
    114
    +// end of singular.hpp

  • src/ftinspect/widgets/fontsizeselector.cpp
    1
    +// fontsizeselector.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "fontsizeselector.hpp"
    
    6
    +
    
    7
    +#include "../engine/engine.hpp"
    
    8
    +
    
    9
    +#include <algorithm>
    
    10
    +
    
    11
    +FontSizeSelector::FontSizeSelector(QWidget* parent, 
    
    12
    +                                   bool zoomNewLine,
    
    13
    +                                   bool continuousView)
    
    14
    +: QWidget(parent), continuousView_(continuousView)
    
    15
    +{
    
    16
    +  createLayout(zoomNewLine);
    
    17
    +  createConnections();
    
    18
    +  setDefaults();
    
    19
    +}
    
    20
    +
    
    21
    +
    
    22
    +double
    
    23
    +FontSizeSelector::selectedSize()
    
    24
    +{
    
    25
    +  return sizeDoubleSpinBox_->value();
    
    26
    +}
    
    27
    +
    
    28
    +
    
    29
    +FontSizeSelector::Units
    
    30
    +FontSizeSelector::selectedUnit()
    
    31
    +{
    
    32
    +  return static_cast<Units>(unitsComboBox_->currentIndex());
    
    33
    +}
    
    34
    +
    
    35
    +
    
    36
    +double
    
    37
    +FontSizeSelector::zoomFactor()
    
    38
    +{
    
    39
    +  if (continuousView_)
    
    40
    +    return zoomSpinBox_->value();
    
    41
    +  return static_cast<int>(zoomSpinBox_->value());
    
    42
    +}
    
    43
    +
    
    44
    +
    
    45
    +void
    
    46
    +FontSizeSelector::setSizePixel(int sizePixel)
    
    47
    +{
    
    48
    +  sizeDoubleSpinBox_->setValue(sizePixel);
    
    49
    +  unitsComboBox_->setCurrentIndex(Units_px);
    
    50
    +}
    
    51
    +
    
    52
    +
    
    53
    +void
    
    54
    +FontSizeSelector::setSizePoint(double sizePoint)
    
    55
    +{
    
    56
    +  sizeDoubleSpinBox_->setValue(sizePoint);
    
    57
    +  unitsComboBox_->setCurrentIndex(Units_pt);
    
    58
    +}
    
    59
    +
    
    60
    +
    
    61
    +void
    
    62
    +FontSizeSelector::setZoomFactor(double zoomFactor)
    
    63
    +{
    
    64
    +  if (continuousView_)
    
    65
    +    zoomSpinBox_->setValue(zoomFactor);
    
    66
    +  zoomSpinBox_->setValue(static_cast<int>(zoomFactor));
    
    67
    +}
    
    68
    +
    
    69
    +
    
    70
    +void
    
    71
    +FontSizeSelector::reloadFromFont(Engine* engine)
    
    72
    +{
    
    73
    +  // TODO: update available sizes.
    
    74
    +  checkFixedSizeAndEmit();
    
    75
    +}
    
    76
    +
    
    77
    +
    
    78
    +void
    
    79
    +FontSizeSelector::applyToEngine(Engine* engine)
    
    80
    +{
    
    81
    +  // Spinbox value cannot become negative
    
    82
    +  engine->setDPI(dpiSpinBox_->value());
    
    83
    +
    
    84
    +  if (unitsComboBox_->currentIndex() == Units_px)
    
    85
    +    engine->setSizeByPixel(sizeDoubleSpinBox_->value());
    
    86
    +  else
    
    87
    +    engine->setSizeByPoint(sizeDoubleSpinBox_->value());
    
    88
    +}
    
    89
    +
    
    90
    +
    
    91
    +void
    
    92
    +FontSizeSelector::handleWheelResizeBySteps(int steps)
    
    93
    +{
    
    94
    +  double sizeAfter = sizeDoubleSpinBox_->value()
    
    95
    +                       + steps * sizeDoubleSpinBox_->singleStep();
    
    96
    +  sizeAfter = std::max(sizeDoubleSpinBox_->minimum(),
    
    97
    +                       std::min(sizeAfter, sizeDoubleSpinBox_->maximum()));
    
    98
    +  sizeDoubleSpinBox_->setValue(sizeAfter);
    
    99
    +}
    
    100
    +
    
    101
    +
    
    102
    +void
    
    103
    +FontSizeSelector::handleWheelZoomBySteps(int steps)
    
    104
    +{
    
    105
    +  double zoomAfter = zoomSpinBox_->value()
    
    106
    +                     + steps * zoomSpinBox_->singleStep();
    
    107
    +  zoomAfter = std::max(zoomSpinBox_->minimum(),
    
    108
    +                       std::min(zoomAfter, zoomSpinBox_->maximum()));
    
    109
    +  zoomSpinBox_->setValue(zoomAfter);
    
    110
    +}
    
    111
    +
    
    112
    +
    
    113
    +void
    
    114
    +FontSizeSelector::handleWheelResizeFromGrid(QWheelEvent* event)
    
    115
    +{
    
    116
    +  int numSteps = event->angleDelta().y() / 120;
    
    117
    +  handleWheelResizeBySteps(numSteps);
    
    118
    +}
    
    119
    +
    
    120
    +
    
    121
    +bool
    
    122
    +FontSizeSelector::handleKeyEvent(QKeyEvent const* keyEvent)
    
    123
    +{
    
    124
    +  if (!keyEvent)
    
    125
    +    return false;
    
    126
    +  auto modifiers = keyEvent->modifiers();
    
    127
    +  auto key = keyEvent->key();
    
    128
    +  if ((modifiers == Qt::ShiftModifier
    
    129
    +       || modifiers == (Qt::ShiftModifier | Qt::KeypadModifier))
    
    130
    +      && (key == Qt::Key_Plus 
    
    131
    +          || key == Qt::Key_Minus
    
    132
    +          || key == Qt::Key_Underscore
    
    133
    +          || key == Qt::Key_Equal
    
    134
    +          || key == Qt::Key_ParenRight))
    
    135
    +  {
    
    136
    +    if (key == Qt::Key_Plus || key == Qt::Key_Equal)
    
    137
    +      handleWheelResizeBySteps(1);
    
    138
    +    else if (key == Qt::Key_Minus
    
    139
    +             || key == Qt::Key_Underscore)
    
    140
    +      handleWheelResizeBySteps(-1);
    
    141
    +    else if (key == Qt::Key_ParenRight)
    
    142
    +      setDefaults(true);
    
    143
    +    return true;
    
    144
    +  }
    
    145
    +  return false;
    
    146
    +}
    
    147
    +
    
    148
    +
    
    149
    +void
    
    150
    +FontSizeSelector::installEventFilterForWidget(QWidget* widget)
    
    151
    +{
    
    152
    +  widget->installEventFilter(this);
    
    153
    +}
    
    154
    +
    
    155
    +
    
    156
    +bool
    
    157
    +FontSizeSelector::eventFilter(QObject* watched,
    
    158
    +                              QEvent* event)
    
    159
    +{
    
    160
    +  if (event->type() == QEvent::KeyPress)
    
    161
    +  {
    
    162
    +    auto keyEvent = dynamic_cast<QKeyEvent*>(event);
    
    163
    +    if (handleKeyEvent(keyEvent))
    
    164
    +      return true;
    
    165
    +  }
    
    166
    +  return QWidget::eventFilter(watched, event);
    
    167
    +}
    
    168
    +
    
    169
    +
    
    170
    +void
    
    171
    +FontSizeSelector::checkUnits()
    
    172
    +{
    
    173
    +  int index = unitsComboBox_->currentIndex();
    
    174
    +
    
    175
    +  if (index == Units_px)
    
    176
    +  {
    
    177
    +    dpiLabel_->setEnabled(false);
    
    178
    +    dpiSpinBox_->setEnabled(false);
    
    179
    +    sizeDoubleSpinBox_->setSingleStep(1);
    
    180
    +
    
    181
    +    QSignalBlocker blocker(sizeDoubleSpinBox_);
    
    182
    +    sizeDoubleSpinBox_->setValue(qRound(sizeDoubleSpinBox_->value()));
    
    183
    +  }
    
    184
    +  else
    
    185
    +  {
    
    186
    +    dpiLabel_->setEnabled(true);
    
    187
    +    dpiSpinBox_->setEnabled(true);
    
    188
    +    sizeDoubleSpinBox_->setSingleStep(0.5);
    
    189
    +  }
    
    190
    +
    
    191
    +  emit valueChanged();
    
    192
    +}
    
    193
    +
    
    194
    +
    
    195
    +void
    
    196
    +FontSizeSelector::createLayout(bool zoomNewLine)
    
    197
    +{
    
    198
    +  sizeLabel_ = new QLabel(tr("Size "), this);
    
    199
    +  sizeLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    200
    +  sizeDoubleSpinBox_ = new QDoubleSpinBox(this);
    
    201
    +  sizeDoubleSpinBox_->setAlignment(Qt::AlignRight);
    
    202
    +  sizeDoubleSpinBox_->setDecimals(1);
    
    203
    +  sizeDoubleSpinBox_->setRange(1, 500);
    
    204
    +  sizeLabel_->setBuddy(sizeDoubleSpinBox_);
    
    205
    +
    
    206
    +  unitsComboBox_ = new QComboBox(this);
    
    207
    +  unitsComboBox_->insertItem(Units_px, "px");
    
    208
    +  unitsComboBox_->insertItem(Units_pt, "pt");
    
    209
    +
    
    210
    +  dpiLabel_ = new QLabel(tr("DPI "), this);
    
    211
    +  dpiLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    212
    +  dpiSpinBox_ = new QSpinBox(this);
    
    213
    +  dpiSpinBox_->setAlignment(Qt::AlignRight);
    
    214
    +  dpiSpinBox_->setRange(10, 600);
    
    215
    +  dpiLabel_->setBuddy(dpiSpinBox_);
    
    216
    +
    
    217
    +  zoomLabel_ = new QLabel(tr("Zoom Factor "), this);
    
    218
    +  zoomLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    219
    +  zoomSpinBox_ = new ZoomSpinBox(this, continuousView_);
    
    220
    +  zoomSpinBox_->setAlignment(Qt::AlignRight);
    
    221
    +  zoomLabel_->setBuddy(zoomSpinBox_);
    
    222
    +
    
    223
    +  // Tooltips
    
    224
    +  sizeDoubleSpinBox_->setToolTip(
    
    225
    +    tr("Size value (will be limited to available sizes if\nthe current font "
    
    226
    +       "is not scalable)."));
    
    227
    +  unitsComboBox_->setToolTip(tr("Unit for the size value (force to pixel if\n"
    
    228
    +                                "the current font is not scalable)."));
    
    229
    +  dpiSpinBox_->setToolTip(
    
    230
    +    tr("DPI for the point size value (only valid when the unit is point)."));
    
    231
    +  zoomSpinBox_->setToolTip(tr("Adjust zoom."));
    
    232
    +
    
    233
    +  // Layouting
    
    234
    +  mainLayout_ = new QVBoxLayout;
    
    235
    +  upLayout_ = new QHBoxLayout;
    
    236
    +  upLayout_->addStretch(1);
    
    237
    +  upLayout_->addWidget(sizeLabel_);
    
    238
    +  upLayout_->addWidget(sizeDoubleSpinBox_);
    
    239
    +  upLayout_->addWidget(unitsComboBox_);
    
    240
    +  upLayout_->addStretch(1);
    
    241
    +  upLayout_->addWidget(dpiLabel_);
    
    242
    +  upLayout_->addWidget(dpiSpinBox_);
    
    243
    +  upLayout_->addStretch(1);
    
    244
    +  if (!zoomNewLine)
    
    245
    +  {
    
    246
    +    upLayout_->addWidget(zoomLabel_);
    
    247
    +    upLayout_->addWidget(zoomSpinBox_);
    
    248
    +    upLayout_->addStretch(1);
    
    249
    +    mainLayout_->addLayout(upLayout_);
    
    250
    +  }
    
    251
    +  else
    
    252
    +  {
    
    253
    +    downLayout_ = new QHBoxLayout;
    
    254
    +    downLayout_->addWidget(zoomLabel_);
    
    255
    +    downLayout_->addWidget(zoomSpinBox_, 1);
    
    256
    +    mainLayout_->addLayout(upLayout_);
    
    257
    +    mainLayout_->addLayout(downLayout_);
    
    258
    +  }
    
    259
    +
    
    260
    +  setLayout(mainLayout_);
    
    261
    +  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    262
    +}
    
    263
    +
    
    264
    +
    
    265
    +void
    
    266
    +FontSizeSelector::createConnections()
    
    267
    +{
    
    268
    +  connect(sizeDoubleSpinBox_, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    269
    +          this, &FontSizeSelector::checkFixedSizeAndEmit);
    
    270
    +  connect(unitsComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    271
    +          this, &FontSizeSelector::checkUnits);
    
    272
    +  connect(dpiSpinBox_, QOverload<int>::of(&QSpinBox::valueChanged),
    
    273
    +          this, &FontSizeSelector::checkFixedSizeAndEmit);
    
    274
    +  connect(zoomSpinBox_, QOverload<double>::of(&ZoomSpinBox::valueChanged),
    
    275
    +          this, &FontSizeSelector::valueChanged);
    
    276
    +}
    
    277
    +
    
    278
    +
    
    279
    +void
    
    280
    +FontSizeSelector::setDefaults(bool sizeOnly)
    
    281
    +{
    
    282
    +  lastValue_ = 20;
    
    283
    +  sizeDoubleSpinBox_->setValue(lastValue_);
    
    284
    +  if (sizeOnly)
    
    285
    +    return;
    
    286
    +  dpiSpinBox_->setValue(96);
    
    287
    +  checkUnits();
    
    288
    +}
    
    289
    +
    
    290
    +
    
    291
    +void
    
    292
    +FontSizeSelector::checkFixedSizeAndEmit()
    
    293
    +{
    
    294
    +  // TODO: check fixed sizes, coerce to available sizes.
    
    295
    +  emit valueChanged();
    
    296
    +}
    
    297
    +
    
    298
    +
    
    299
    +// end of fontsizeselector.cpp

  • src/ftinspect/widgets/fontsizeselector.hpp
    1
    +// fontsizeselector.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include "customwidgets.hpp"
    
    8
    +
    
    9
    +#include <QComboBox>
    
    10
    +#include <QDoubleSpinBox>
    
    11
    +#include <QLabel>
    
    12
    +#include <QWidget>
    
    13
    +#include <QBoxLayout>
    
    14
    +#include <QWheelEvent>
    
    15
    +
    
    16
    +class Engine;
    
    17
    +class FontSizeSelector : public QWidget
    
    18
    +{
    
    19
    +  Q_OBJECT
    
    20
    +
    
    21
    +public:
    
    22
    +  // For the continuous view mode, see `ZoomSpinBox`'s documentation.
    
    23
    +  FontSizeSelector(QWidget* parent, bool zoomNewLine, bool continuousView);
    
    24
    +  ~FontSizeSelector() override = default;
    
    25
    +
    
    26
    +  enum Units : int
    
    27
    +  {
    
    28
    +    Units_px,
    
    29
    +    Units_pt
    
    30
    +  };
    
    31
    +
    
    32
    +  //////// Getters
    
    33
    +  double selectedSize();
    
    34
    +  Units selectedUnit();
    
    35
    +  double zoomFactor();
    
    36
    +  //////// Setters
    
    37
    +  void setSizePixel(int sizePixel);
    
    38
    +  void setSizePoint(double sizePoint);
    
    39
    +  void setZoomFactor(double zoomFactor);
    
    40
    +
    
    41
    +  void reloadFromFont(Engine* engine);
    
    42
    +  void applyToEngine(Engine* engine);
    
    43
    +  void handleWheelResizeBySteps(int steps);
    
    44
    +  void handleWheelZoomBySteps(int steps);
    
    45
    +  void handleWheelResizeFromGrid(QWheelEvent* event);
    
    46
    +  bool handleKeyEvent(QKeyEvent const* keyEvent);
    
    47
    +  void installEventFilterForWidget(QWidget* widget);
    
    48
    +
    
    49
    +protected:
    
    50
    +  bool eventFilter(QObject* watched, QEvent* event) override;
    
    51
    +
    
    52
    +signals:
    
    53
    +  void valueChanged();
    
    54
    +
    
    55
    +private:
    
    56
    +  QLabel* sizeLabel_;
    
    57
    +  QLabel* dpiLabel_;
    
    58
    +  QLabel* zoomLabel_;
    
    59
    +
    
    60
    +  QDoubleSpinBox* sizeDoubleSpinBox_;
    
    61
    +  QComboBox* unitsComboBox_;
    
    62
    +  QSpinBox* dpiSpinBox_;
    
    63
    +  ZoomSpinBox* zoomSpinBox_;
    
    64
    +
    
    65
    +  // Sometimes we need to split 2 lines
    
    66
    +  QHBoxLayout* upLayout_;
    
    67
    +  QHBoxLayout* downLayout_;
    
    68
    +  QVBoxLayout* mainLayout_;
    
    69
    +
    
    70
    +  bool continuousView_;
    
    71
    +  double lastValue_;
    
    72
    +
    
    73
    +  void createLayout(bool zoomNewLine);
    
    74
    +  void createConnections();
    
    75
    +  void setDefaults(bool sizeOnly = false);
    
    76
    +
    
    77
    +  void checkUnits();
    
    78
    +  void checkFixedSizeAndEmit();
    
    79
    +};
    
    80
    +
    
    81
    +
    
    82
    +// end of fontsizeselector.hpp

  • src/ftinspect/widgets/glyphindexselector.cpp
    1
    +// glyphindexselector.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 Charlie Jiang.
    
    4
    +
    
    5
    +#include "glyphindexselector.hpp"
    
    6
    +
    
    7
    +#include "../uihelper.hpp"
    
    8
    +
    
    9
    +#include <climits>
    
    10
    +
    
    11
    +GlyphIndexSelector::GlyphIndexSelector(QWidget* parent)
    
    12
    +: QWidget(parent)
    
    13
    +{
    
    14
    +  numberRenderer_ = &GlyphIndexSelector::renderNumberDefault;
    
    15
    +
    
    16
    +  createLayout();
    
    17
    +  createConnections();
    
    18
    +  showingCount_ = 0;
    
    19
    +}
    
    20
    +
    
    21
    +
    
    22
    +void
    
    23
    +GlyphIndexSelector::setMinMax(int min,
    
    24
    +                              int max)
    
    25
    +{
    
    26
    +  // Don't emit events during setting
    
    27
    +  auto eventState = blockSignals(true);
    
    28
    +  indexSpinBox_->setMinimum(min);
    
    29
    +  indexSpinBox_->setMaximum(qBound(0, max, INT_MAX));
    
    30
    +  indexSpinBox_->setValue(qBound(indexSpinBox_->minimum(),
    
    31
    +                                 indexSpinBox_->value(),
    
    32
    +                                 indexSpinBox_->maximum()));
    
    33
    +  blockSignals(eventState);
    
    34
    +
    
    35
    +  updateLabel();
    
    36
    +}
    
    37
    +
    
    38
    +
    
    39
    +void
    
    40
    +GlyphIndexSelector::setShowingCount(int showingCount)
    
    41
    +{
    
    42
    +  showingCount_ = showingCount;
    
    43
    +  updateLabel();
    
    44
    +}
    
    45
    +
    
    46
    +
    
    47
    +void
    
    48
    +GlyphIndexSelector::setSingleMode(bool singleMode)
    
    49
    +{
    
    50
    +  singleMode_ = singleMode;
    
    51
    +  updateLabel();
    
    52
    +}
    
    53
    +
    
    54
    +
    
    55
    +void
    
    56
    +GlyphIndexSelector::setCurrentIndex(int index, bool forceUpdate)
    
    57
    +{
    
    58
    +  // to avoid unnecessary update, if force update is enabled
    
    59
    +  // then the `setValue` shouldn't trigger update signal from `this`
    
    60
    +  // but we still need `updateLabel`, so block `this` only
    
    61
    +  auto state = blockSignals(forceUpdate);
    
    62
    +  indexSpinBox_->setValue(index);
    
    63
    +  blockSignals(state);
    
    64
    +  
    
    65
    +  if (forceUpdate)
    
    66
    +    emit currentIndexChanged(indexSpinBox_->value());
    
    67
    +}
    
    68
    +
    
    69
    +
    
    70
    +int
    
    71
    +GlyphIndexSelector::currentIndex()
    
    72
    +{
    
    73
    +  return indexSpinBox_->value();
    
    74
    +}
    
    75
    +
    
    76
    +
    
    77
    +void
    
    78
    +GlyphIndexSelector::setNumberRenderer(std::function<QString(int)> renderer)
    
    79
    +{
    
    80
    +  numberRenderer_ = std::move(renderer);
    
    81
    +}
    
    82
    +
    
    83
    +
    
    84
    +void
    
    85
    +GlyphIndexSelector::resizeEvent(QResizeEvent* event)
    
    86
    +{
    
    87
    +  QWidget::resizeEvent(event);
    
    88
    +  auto minimumWidth = minimumSizeHint().width();
    
    89
    +  if (toEndButton_->isVisible())
    
    90
    +  {
    
    91
    +    if (width() < minimumWidth)
    
    92
    +      navigationWidget_->setVisible(false);
    
    93
    +  }
    
    94
    +  else if (navigationWidget_->minimumSizeHint().width() + minimumWidth 
    
    95
    +           <= width())
    
    96
    +    navigationWidget_->setVisible(true);
    
    97
    +}
    
    98
    +
    
    99
    +
    
    100
    +void
    
    101
    +GlyphIndexSelector::adjustIndex(int delta)
    
    102
    +{
    
    103
    +  {
    
    104
    +    QSignalBlocker blocker(this);
    
    105
    +    indexSpinBox_->setValue(qBound(indexSpinBox_->minimum(),
    
    106
    +                                   indexSpinBox_->value() + delta,
    
    107
    +                                   indexSpinBox_->maximum()));
    
    108
    +  }
    
    109
    +  emitValueChanged();
    
    110
    +}
    
    111
    +
    
    112
    +
    
    113
    +void
    
    114
    +GlyphIndexSelector::emitValueChanged()
    
    115
    +{
    
    116
    +  emit currentIndexChanged(indexSpinBox_->value());
    
    117
    +  updateLabel();
    
    118
    +}
    
    119
    +
    
    120
    +
    
    121
    +void
    
    122
    +GlyphIndexSelector::updateLabel()
    
    123
    +{
    
    124
    +  if (singleMode_)
    
    125
    +    indexLabel_->setText(QString("%1\nLimit: %2")
    
    126
    +                           .arg(numberRenderer_(indexSpinBox_->value()))
    
    127
    +                           .arg(numberRenderer_(indexSpinBox_->maximum())));
    
    128
    +  else
    
    129
    +    indexLabel_->setText(
    
    130
    +      QString("%1~%2\nLimit: %4")
    
    131
    +        .arg(numberRenderer_(indexSpinBox_->value()))
    
    132
    +        .arg(numberRenderer_(
    
    133
    +          qBound(indexSpinBox_->value(),
    
    134
    +                 indexSpinBox_->value() + showingCount_ - 1, INT_MAX)))
    
    135
    +        .arg(numberRenderer_(indexSpinBox_->maximum())));
    
    136
    +}
    
    137
    +
    
    138
    +
    
    139
    +void
    
    140
    +GlyphIndexSelector::createLayout()
    
    141
    +{
    
    142
    +  navigationWidget_ = new QWidget(this);
    
    143
    +  toStartButton_ = new QPushButton("|<", this);
    
    144
    +  toM1000Button_ = new QPushButton("-1000", this);
    
    145
    +  toM100Button_ = new QPushButton("-100", this);
    
    146
    +  toM10Button_ = new QPushButton("-10", this);
    
    147
    +  toM1Button_ = new QPushButton("-1", this);
    
    148
    +  toP1Button_ = new QPushButton("+1", this);
    
    149
    +  toP10Button_ = new QPushButton("+10", this);
    
    150
    +  toP100Button_ = new QPushButton("+100", this);
    
    151
    +  toP1000Button_ = new QPushButton("+1000", this);
    
    152
    +  toEndButton_ = new QPushButton(">|", this);
    
    153
    +  
    
    154
    +  indexSpinBox_ = new QSpinBox(this);
    
    155
    +  indexSpinBox_->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
    
    156
    +  indexSpinBox_->setButtonSymbols(QAbstractSpinBox::NoButtons);
    
    157
    +  indexSpinBox_->setRange(0, 0);
    
    158
    +  indexSpinBox_->setFixedWidth(80);
    
    159
    +  indexSpinBox_->setWrapping(false);
    
    160
    +  indexSpinBox_->setKeyboardTracking(false);
    
    161
    +
    
    162
    +  indexLabel_ = new QLabel("0\nLimit: 0");
    
    163
    +  indexLabel_->setMinimumWidth(200);
    
    164
    +
    
    165
    +  setButtonNarrowest(toStartButton_);
    
    166
    +  setButtonNarrowest(toM1000Button_);
    
    167
    +  setButtonNarrowest(toM100Button_);
    
    168
    +  setButtonNarrowest(toM10Button_);
    
    169
    +  setButtonNarrowest(toM1Button_);
    
    170
    +  setButtonNarrowest(toP1Button_);
    
    171
    +  setButtonNarrowest(toP10Button_);
    
    172
    +  setButtonNarrowest(toP100Button_);
    
    173
    +  setButtonNarrowest(toP1000Button_);
    
    174
    +  setButtonNarrowest(toEndButton_);
    
    175
    +
    
    176
    +  // Toltips
    
    177
    +  indexSpinBox_->setToolTip("Current glyph index.");
    
    178
    +  indexLabel_->setToolTip("Current glyph index/range and the max index.");
    
    179
    +
    
    180
    +  // Layouting
    
    181
    +  navigationLayout_ = new QHBoxLayout;
    
    182
    +  navigationLayout_->setSpacing(0);
    
    183
    +  navigationLayout_->addWidget(toStartButton_);
    
    184
    +  navigationLayout_->addWidget(toM1000Button_);
    
    185
    +  navigationLayout_->addWidget(toM100Button_);
    
    186
    +  navigationLayout_->addWidget(toM10Button_);
    
    187
    +  navigationLayout_->addWidget(toM1Button_);
    
    188
    +  navigationLayout_->addWidget(toP1Button_);
    
    189
    +  navigationLayout_->addWidget(toP10Button_);
    
    190
    +  navigationLayout_->addWidget(toP100Button_);
    
    191
    +  navigationLayout_->addWidget(toP1000Button_);
    
    192
    +  navigationLayout_->addWidget(toEndButton_);
    
    193
    +  navigationWidget_->setLayout(navigationLayout_);
    
    194
    +
    
    195
    +  layout_ = new QHBoxLayout;
    
    196
    +  layout_->setSpacing(0);
    
    197
    +  layout_->addStretch(3);
    
    198
    +  layout_->addWidget(navigationWidget_);
    
    199
    +  layout_->addStretch(1);
    
    200
    +  layout_->addWidget(indexSpinBox_);
    
    201
    +  layout_->addStretch(1);
    
    202
    +  layout_->addWidget(indexLabel_);
    
    203
    +  layout_->addStretch(3);
    
    204
    +
    
    205
    +  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    206
    +  setLayout(layout_);
    
    207
    +}
    
    208
    +
    
    209
    +void
    
    210
    +GlyphIndexSelector::createConnections()
    
    211
    +{
    
    212
    +  connect(indexSpinBox_, QOverload<int>::of(&QSpinBox::valueChanged), 
    
    213
    +          this, &GlyphIndexSelector::emitValueChanged);
    
    214
    +
    
    215
    +  glyphNavigationMapper_ = new QSignalMapper(this);
    
    216
    +  connect(glyphNavigationMapper_, &QSignalMapper::mappedInt,
    
    217
    +          this, &GlyphIndexSelector::adjustIndex);
    
    218
    +
    
    219
    +  connect(toStartButton_, &QPushButton::clicked,
    
    220
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    221
    +  connect(toM1000Button_, &QPushButton::clicked,
    
    222
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    223
    +  connect(toM100Button_, &QPushButton::clicked,
    
    224
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    225
    +  connect(toM10Button_, &QPushButton::clicked,
    
    226
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    227
    +  connect(toM1Button_, &QPushButton::clicked,
    
    228
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    229
    +  connect(toP1Button_, &QPushButton::clicked,
    
    230
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    231
    +  connect(toP10Button_, &QPushButton::clicked,
    
    232
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    233
    +  connect(toP100Button_, &QPushButton::clicked,
    
    234
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    235
    +  connect(toP1000Button_, &QPushButton::clicked,
    
    236
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    237
    +  connect(toEndButton_, &QPushButton::clicked,
    
    238
    +          glyphNavigationMapper_, QOverload<>::of(&QSignalMapper::map));
    
    239
    +
    
    240
    +  glyphNavigationMapper_->setMapping(toStartButton_, -0x10000);
    
    241
    +  glyphNavigationMapper_->setMapping(toM1000Button_, -1000);
    
    242
    +  glyphNavigationMapper_->setMapping(toM100Button_, -100);
    
    243
    +  glyphNavigationMapper_->setMapping(toM10Button_, -10);
    
    244
    +  glyphNavigationMapper_->setMapping(toM1Button_, -1);
    
    245
    +  glyphNavigationMapper_->setMapping(toP1Button_, 1);
    
    246
    +  glyphNavigationMapper_->setMapping(toP10Button_, 10);
    
    247
    +  glyphNavigationMapper_->setMapping(toP100Button_, 100);
    
    248
    +  glyphNavigationMapper_->setMapping(toP1000Button_, 1000);
    
    249
    +  glyphNavigationMapper_->setMapping(toEndButton_, 0x10000);
    
    250
    +}
    
    251
    +
    
    252
    +
    
    253
    +QString
    
    254
    +GlyphIndexSelector::renderNumberDefault(int i)
    
    255
    +{
    
    256
    +  return QString::number(i);
    
    257
    +}
    
    258
    +
    
    259
    +
    
    260
    +// end of glyphindexselector.cpp

  • src/ftinspect/widgets/glyphindexselector.hpp
    1
    +// glyphindexselector.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include <functional>
    
    8
    +#include <QWidget>
    
    9
    +#include <QPushButton>
    
    10
    +#include <QSpinBox>
    
    11
    +#include <QSignalMapper>
    
    12
    +#include <QHBoxLayout>
    
    13
    +#include <QLabel>
    
    14
    +
    
    15
    +class GlyphIndexSelector
    
    16
    +: public QWidget
    
    17
    +{
    
    18
    +  Q_OBJECT
    
    19
    +public:
    
    20
    +  GlyphIndexSelector(QWidget* parent);
    
    21
    +  ~GlyphIndexSelector() override = default;
    
    22
    +
    
    23
    +  // Will never trigger repaint!
    
    24
    +  void setMinMax(int min, int max);
    
    25
    +  void setShowingCount(int showingCount);
    
    26
    +
    
    27
    +  // Single mode will display single glyph index instead of a range.
    
    28
    +  void setSingleMode(bool singleMode);
    
    29
    +
    
    30
    +  void setCurrentIndex(int index, bool forceUpdate = false);
    
    31
    +  int currentIndex();
    
    32
    +
    
    33
    +  void setNumberRenderer(std::function<QString(int)> renderer);
    
    34
    +
    
    35
    +signals:
    
    36
    +  void currentIndexChanged(int index);
    
    37
    +
    
    38
    +protected:
    
    39
    +  void resizeEvent(QResizeEvent* event) override;
    
    40
    +  
    
    41
    +private:
    
    42
    +  bool singleMode_ = true;
    
    43
    +  int showingCount_;
    
    44
    +  std::function<QString(int)> numberRenderer_;
    
    45
    +
    
    46
    +  // min, max and current status are held by `indexSpinBox_`
    
    47
    +  QWidget* navigationWidget_;
    
    48
    +  QPushButton* toEndButton_;
    
    49
    +  QPushButton* toM1000Button_;
    
    50
    +  QPushButton* toM100Button_;
    
    51
    +  QPushButton* toM10Button_;
    
    52
    +  QPushButton* toM1Button_;
    
    53
    +  QPushButton* toP1000Button_;
    
    54
    +  QPushButton* toP100Button_;
    
    55
    +  QPushButton* toP10Button_;
    
    56
    +  QPushButton* toP1Button_;
    
    57
    +  QPushButton* toStartButton_;
    
    58
    +
    
    59
    +  QLabel* indexLabel_;
    
    60
    +  QSpinBox* indexSpinBox_;
    
    61
    +
    
    62
    +  QHBoxLayout* navigationLayout_;
    
    63
    +  QHBoxLayout* layout_;
    
    64
    +
    
    65
    +  QSignalMapper* glyphNavigationMapper_;
    
    66
    +
    
    67
    +  void createLayout();
    
    68
    +  void createConnections();
    
    69
    +
    
    70
    +  void adjustIndex(int delta);
    
    71
    +  void emitValueChanged();
    
    72
    +  void updateLabel();
    
    73
    +
    
    74
    +  static QString renderNumberDefault(int i);
    
    75
    +};
    
    76
    +
    
    77
    +
    
    78
    +// end of glyphindexselector.hpp

  • src/ftinspect/widgets/tripletselector.cpp
    1
    +// tripletselector.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "tripletselector.hpp"
    
    6
    +
    
    7
    +#include "../engine/engine.hpp"
    
    8
    +
    
    9
    +#include <functional>
    
    10
    +
    
    11
    +TripletSelector::TripletSelector(QWidget* parent,
    
    12
    +                                 Engine* engine)
    
    13
    +: QWidget(parent),
    
    14
    +  engine_(engine)
    
    15
    +{
    
    16
    +  createLayout();
    
    17
    +  createConnections();
    
    18
    +  checkButtons();
    
    19
    +}
    
    20
    +
    
    21
    +
    
    22
    +TripletSelector::~TripletSelector()
    
    23
    +{
    
    24
    +}
    
    25
    +
    
    26
    +
    
    27
    +void
    
    28
    +TripletSelector::repopulateFonts()
    
    29
    +{
    
    30
    +  auto oldSize = fontComboBox_->count();
    
    31
    +  auto oldIndex = fontComboBox_->currentIndex();
    
    32
    +
    
    33
    +  {
    
    34
    +    QSignalBlocker blk(fontComboBox_);
    
    35
    +    QSignalBlocker blk2(faceComboBox_);
    
    36
    +    QSignalBlocker blk3(niComboBox_);
    
    37
    +    fontComboBox_->clear();
    
    38
    +    
    
    39
    +    auto& ffm = engine_->fontFileManager();
    
    40
    +    auto newSize = ffm.size();
    
    41
    +    for (int i = 0; i < newSize; i++)
    
    42
    +    {
    
    43
    +      auto& info = ffm[i];
    
    44
    +      auto name = info.filePath();
    
    45
    +      auto displayName = info.fileName();
    
    46
    +      if (info.isSymbolicLink())
    
    47
    +        displayName += " [symlink]";
    
    48
    +
    
    49
    +      fontComboBox_->addItem(displayName, name);
    
    50
    +    }
    
    51
    +
    
    52
    +    if (newSize > oldSize)
    
    53
    +    {
    
    54
    +      // if we have new fonts, set the current index to the first new one
    
    55
    +      fontComboBox_->setCurrentIndex(oldSize);
    
    56
    +    }
    
    57
    +    else if (newSize < oldSize)
    
    58
    +    {
    
    59
    +      if (oldIndex >= newSize)
    
    60
    +        oldIndex = newSize - 1;
    
    61
    +      if (oldIndex < 0)
    
    62
    +        oldIndex = -1;
    
    63
    +      fontComboBox_->setCurrentIndex(oldIndex);
    
    64
    +    }
    
    65
    +
    
    66
    +    // Note no signal will be emitted from any combobox until this block ends
    
    67
    +  }
    
    68
    +
    
    69
    +  // This will check buttons & reload the triplet
    
    70
    +  repopulateFaces();
    
    71
    +}
    
    72
    +
    
    73
    +
    
    74
    +void
    
    75
    +TripletSelector::repopulateFaces(bool fontSwitched)
    
    76
    +{
    
    77
    +  // Avoid unnecessary recreating, to reduce interruption of user oper
    
    78
    +  auto needToRecreate = fontSwitched;
    
    79
    +  auto oldSize = faceComboBox_->count();
    
    80
    +
    
    81
    +  auto fontIndex = fontComboBox_->currentIndex();
    
    82
    +  auto newSize = engine_->numberOfFaces(fontIndex);
    
    83
    +
    
    84
    +  if (fontIndex < 0 || newSize < 0)
    
    85
    +  {
    
    86
    +    // Clear and go
    
    87
    +    faceComboBox_->clear();
    
    88
    +    // This will check buttons & reload the triplet
    
    89
    +    repopulateNamedInstances(fontSwitched);
    
    90
    +    return;
    
    91
    +  }
    
    92
    +
    
    93
    +  if (newSize != oldSize)
    
    94
    +    needToRecreate = true;
    
    95
    +
    
    96
    +  std::vector<QString> newFaces;
    
    97
    +  newFaces.reserve(newSize);
    
    98
    +  for (long i = 0; i < newSize; i++)
    
    99
    +  {
    
    100
    +    newFaces.emplace_back(engine_->namedInstanceName(fontIndex, i, 0));
    
    101
    +    if (!needToRecreate && newFaces[i] != faceComboBox_->itemData(i))
    
    102
    +      needToRecreate = true;
    
    103
    +  }
    
    104
    +
    
    105
    +  if (!needToRecreate)
    
    106
    +  {
    
    107
    +    // no need to refersh the combobox
    
    108
    +    // This will check buttons & reload the triplet
    
    109
    +    repopulateNamedInstances(fontSwitched);
    
    110
    +    return;
    
    111
    +  }
    
    112
    +
    
    113
    +  {
    
    114
    +    QSignalBlocker blk2(faceComboBox_);
    
    115
    +    QSignalBlocker blk3(niComboBox_);
    
    116
    +    faceComboBox_->clear();
    
    117
    +
    
    118
    +    for (long i = 0; i < newSize; i++)
    
    119
    +    {
    
    120
    +      auto& name = newFaces[i];
    
    121
    +      auto displayName = QString("%1: %2").arg(i).arg(name);
    
    122
    +      faceComboBox_->addItem(displayName, name);
    
    123
    +    }
    
    124
    +
    
    125
    +    faceComboBox_->setCurrentIndex(0);
    
    126
    +    // Note no signal will be emitted from any combobox until this block ends
    
    127
    +  }
    
    128
    +
    
    129
    +  // This will check buttons & reload the triplet
    
    130
    +  repopulateNamedInstances(true);
    
    131
    +}
    
    132
    +
    
    133
    +
    
    134
    +void
    
    135
    +TripletSelector::repopulateNamedInstances(bool fontSwitched)
    
    136
    +{
    
    137
    +  // Avoid unnecessary recreating, to reduce interruption of user oper
    
    138
    +  // Similar to `repopulateFaces`
    
    139
    +  auto needToRecreate = fontSwitched;
    
    140
    +  auto oldSize = niComboBox_->count();
    
    141
    +
    
    142
    +  auto fontIndex = fontComboBox_->currentIndex();
    
    143
    +  auto faceIndex = faceComboBox_->currentIndex();
    
    144
    +  auto newSize = engine_->numberOfNamedInstances(fontIndex, faceIndex);
    
    145
    +
    
    146
    +  if (fontIndex < 0 || faceIndex < 0 || newSize < 0)
    
    147
    +  {
    
    148
    +    // Clear and go, don't forget checking buttons and loading triplet
    
    149
    +    niComboBox_->clear();
    
    150
    +    checkButtons();
    
    151
    +    loadTriplet();
    
    152
    +    return;
    
    153
    +  }
    
    154
    +
    
    155
    +  if (newSize != oldSize)
    
    156
    +    needToRecreate = true;
    
    157
    +
    
    158
    +  std::vector<QString> newFaces;
    
    159
    +  newFaces.reserve(newSize);
    
    160
    +  for (long i = 0; i < newSize; i++)
    
    161
    +  {
    
    162
    +    newFaces.emplace_back(engine_->namedInstanceName(fontIndex, faceIndex, i));
    
    163
    +    if (!needToRecreate && newFaces[i] != niComboBox_->itemData(i))
    
    164
    +      needToRecreate = true;
    
    165
    +  }
    
    166
    +
    
    167
    +  niComboBox_->setEnabled(newSize > 1);
    
    168
    +
    
    169
    +  if (!needToRecreate)
    
    170
    +  {
    
    171
    +    // no need to refersh the combobox
    
    172
    +    checkButtons();
    
    173
    +    loadTriplet();
    
    174
    +    return;
    
    175
    +  }
    
    176
    +
    
    177
    +  {
    
    178
    +    QSignalBlocker blk3(niComboBox_);
    
    179
    +    niComboBox_->clear();
    
    180
    +
    
    181
    +    for (long i = 0; i < newSize; i++)
    
    182
    +    {
    
    183
    +      auto& name = newFaces[i];
    
    184
    +      auto displayName = QString("%1: %2").arg(i).arg(name);
    
    185
    +      if (i == 0)
    
    186
    +        displayName = "* " + displayName;
    
    187
    +      niComboBox_->addItem(displayName, name);
    
    188
    +    }
    
    189
    +
    
    190
    +    niComboBox_->setCurrentIndex(0);
    
    191
    +    // Note no signal will be emitted from any combobox until this block ends
    
    192
    +  }
    
    193
    +
    
    194
    +  checkButtons();
    
    195
    +  loadTriplet();
    
    196
    +}
    
    197
    +
    
    198
    +
    
    199
    +void
    
    200
    +TripletSelector::closeCurrentFont()
    
    201
    +{
    
    202
    +  auto idx = fontComboBox_->currentIndex();
    
    203
    +  if (idx < 0)
    
    204
    +    return;
    
    205
    +  engine_->fontFileManager().remove(idx);
    
    206
    +
    
    207
    +  // show next font after deletion, i.e., retain index if possible
    
    208
    +  int num = engine_->numberOfOpenedFonts();
    
    209
    +  if (num)
    
    210
    +  {
    
    211
    +    if (idx >= num)
    
    212
    +      idx = num - 1;
    
    213
    +  }
    
    214
    +  else
    
    215
    +    idx = -1;
    
    216
    +
    
    217
    +  {
    
    218
    +    // Shut up when repopulating
    
    219
    +    QSignalBlocker blockerThis(this);
    
    220
    +    QSignalBlocker blockerComboBox(fontComboBox_);
    
    221
    +    repopulateFonts();
    
    222
    +  }
    
    223
    +
    
    224
    +  if (idx != -1)
    
    225
    +    faceComboBox_->setCurrentIndex(idx);
    
    226
    +  updateFont();
    
    227
    +}
    
    228
    +
    
    229
    +
    
    230
    +void
    
    231
    +TripletSelector::updateFont()
    
    232
    +{
    
    233
    +  auto idx = fontComboBox_->currentIndex();
    
    234
    +  auto num = engine_->numberOfOpenedFonts();
    
    235
    +  if (idx < 0)
    
    236
    +  {
    
    237
    +    faceComboBox_->clear();
    
    238
    +    niComboBox_->clear();
    
    239
    +
    
    240
    +    checkButtons();
    
    241
    +    loadTriplet();
    
    242
    +    return;
    
    243
    +  }
    
    244
    +
    
    245
    +  if (num <= 0 || idx >= num)
    
    246
    +  {
    
    247
    +    // out of sync: this shouldn't happen
    
    248
    +    repopulateFonts();
    
    249
    +    return;
    
    250
    +  }
    
    251
    +
    
    252
    +  // This will check buttons & reload the triplet
    
    253
    +  repopulateFaces();
    
    254
    +}
    
    255
    +
    
    256
    +
    
    257
    +void
    
    258
    +TripletSelector::updateFace()
    
    259
    +{
    
    260
    +  auto idx = faceComboBox_->currentIndex();
    
    261
    +  auto num = engine_->numberOfFaces(fontComboBox_->currentIndex());
    
    262
    +  
    
    263
    +  if (idx >= num)
    
    264
    +  {
    
    265
    +    // out of sync
    
    266
    +    repopulateFaces();
    
    267
    +    return;
    
    268
    +  }
    
    269
    +
    
    270
    +  // This will check buttons & reload the triplet
    
    271
    +  repopulateNamedInstances();
    
    272
    +}
    
    273
    +
    
    274
    +
    
    275
    +void
    
    276
    +TripletSelector::updateNI()
    
    277
    +{
    
    278
    +  auto idx = niComboBox_->currentIndex();
    
    279
    +  auto num = engine_->numberOfNamedInstances(fontComboBox_->currentIndex(),
    
    280
    +                                             faceComboBox_->currentIndex());
    
    281
    +  
    
    282
    +  if (idx >= num)
    
    283
    +  {
    
    284
    +    // out of sync
    
    285
    +    repopulateNamedInstances();
    
    286
    +    return;
    
    287
    +  }
    
    288
    +
    
    289
    +  checkButtons();
    
    290
    +  loadTriplet();
    
    291
    +}
    
    292
    +
    
    293
    +
    
    294
    +void
    
    295
    +TripletSelector::checkButtons()
    
    296
    +{
    
    297
    +  fontUpButton_->setEnabled(fontComboBox_->currentIndex() > 0);
    
    298
    +  fontDownButton_->setEnabled(fontComboBox_->currentIndex()
    
    299
    +                              < fontComboBox_->count() - 1);
    
    300
    +  closeFontButton_->setEnabled(faceComboBox_->currentIndex() >= 0);
    
    301
    +
    
    302
    +  faceUpButton_->setEnabled(faceComboBox_->currentIndex() > 0);
    
    303
    +  faceDownButton_->setEnabled(faceComboBox_->currentIndex()
    
    304
    +                              < faceComboBox_->count() - 1);
    
    305
    +
    
    306
    +  niUpButton_->setEnabled(niComboBox_->currentIndex() > 0);
    
    307
    +  niDownButton_->setEnabled(niComboBox_->currentIndex()
    
    308
    +                            < niComboBox_->count() - 1);
    
    309
    +}
    
    310
    +
    
    311
    +
    
    312
    +void
    
    313
    +TripletSelector::watchCurrentFont()
    
    314
    +{
    
    315
    +  repopulateFaces(false);
    
    316
    +}
    
    317
    +
    
    318
    +
    
    319
    +void
    
    320
    +TripletSelector::createLayout()
    
    321
    +{
    
    322
    +  fontComboBox_ = new QComboBox(this);
    
    323
    +  faceComboBox_ = new QComboBox(this);
    
    324
    +  niComboBox_   = new QComboBox(this);
    
    325
    +
    
    326
    +  fontComboBox_->setPlaceholderText(tr("No font open"));
    
    327
    +  faceComboBox_->setPlaceholderText(tr("No face available"));
    
    328
    +  niComboBox_->setPlaceholderText(tr("No named instance available"));
    
    329
    +  
    
    330
    +  closeFontButton_ = new QToolButton(this);
    
    331
    +  fontUpButton_    = new QToolButton(this);
    
    332
    +  faceUpButton_    = new QToolButton(this);
    
    333
    +  niUpButton_      = new QToolButton(this);
    
    334
    +  fontDownButton_  = new QToolButton(this);
    
    335
    +  faceDownButton_  = new QToolButton(this);
    
    336
    +  niDownButton_    = new QToolButton(this);
    
    337
    +
    
    338
    +  closeFontButton_->setText(tr("Close"));
    
    339
    +  fontUpButton_   ->setText(tr("\xE2\x86\x91"));
    
    340
    +  faceUpButton_   ->setText(tr("\xE2\x86\x91"));
    
    341
    +  niUpButton_     ->setText(tr("\xE2\x86\x91"));
    
    342
    +  fontDownButton_ ->setText(tr("\xE2\x86\x93"));
    
    343
    +  faceDownButton_ ->setText(tr("\xE2\x86\x93"));
    
    344
    +  niDownButton_   ->setText(tr("\xE2\x86\x93"));
    
    345
    +  
    
    346
    +  fontComboBox_   ->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    
    347
    +  faceComboBox_   ->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    
    348
    +  niComboBox_     ->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    
    349
    +  closeFontButton_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
    
    350
    +  fontUpButton_   ->setFixedSize(30, 30);
    
    351
    +  faceUpButton_   ->setFixedSize(30, 30);
    
    352
    +  niUpButton_     ->setFixedSize(30, 30);
    
    353
    +  fontDownButton_ ->setFixedSize(30, 30);
    
    354
    +  faceDownButton_ ->setFixedSize(30, 30);
    
    355
    +  niDownButton_   ->setFixedSize(30, 30);
    
    356
    +
    
    357
    +  // Tooltips
    
    358
    +  fontComboBox_->setToolTip(tr("Current font"));
    
    359
    +  faceComboBox_->setToolTip(tr("Current subfont (face)"));
    
    360
    +  niComboBox_->setToolTip(
    
    361
    +    tr("Current named instance (only available for variable fonts)"));
    
    362
    +  closeFontButton_->setToolTip(tr("Close current font"));
    
    363
    +  fontUpButton_   ->setToolTip(tr("Previous font"));
    
    364
    +  faceUpButton_   ->setToolTip(tr("Previous subfont (face)"));
    
    365
    +  niUpButton_     ->setToolTip(tr("Previous named instance"));
    
    366
    +  fontDownButton_ ->setToolTip(tr("Next font"));
    
    367
    +  faceDownButton_ ->setToolTip(tr("Next subfont (face)"));
    
    368
    +  niDownButton_   ->setToolTip(tr("Next named instance"));
    
    369
    +
    
    370
    +  // Layouting
    
    371
    +  layout_ = new QHBoxLayout;
    
    372
    +  layout_->setSpacing(0);
    
    373
    +  layout_->setContentsMargins(0, 0, 0, 0);
    
    374
    +
    
    375
    +  layout_->addWidget(fontComboBox_);
    
    376
    +  layout_->addWidget(fontUpButton_);
    
    377
    +  layout_->addWidget(fontDownButton_);
    
    378
    +  layout_->addWidget(closeFontButton_);
    
    379
    +  layout_->addWidget(faceComboBox_);
    
    380
    +  layout_->addWidget(faceUpButton_);
    
    381
    +  layout_->addWidget(faceDownButton_);
    
    382
    +  layout_->addWidget(niComboBox_);
    
    383
    +  layout_->addWidget(niUpButton_);
    
    384
    +  layout_->addWidget(niDownButton_);
    
    385
    +
    
    386
    +  setFixedHeight(30);
    
    387
    +  setLayout(layout_);
    
    388
    +  layout_->setContentsMargins(0, 0, 0, 0);
    
    389
    +}
    
    390
    +
    
    391
    +
    
    392
    +void
    
    393
    +TripletSelector::createConnections()
    
    394
    +{
    
    395
    +  connect(fontComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    396
    +          this, &TripletSelector::updateFont);
    
    397
    +  connect(faceComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    398
    +          this, &TripletSelector::updateFace);
    
    399
    +  connect(niComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    400
    +          this, &TripletSelector::updateNI);
    
    401
    +
    
    402
    +  connect(closeFontButton_, &QToolButton::clicked, 
    
    403
    +          this, &TripletSelector::closeCurrentFont);
    
    404
    +  connect(fontUpButton_   , &QToolButton::clicked, 
    
    405
    +          this, 
    
    406
    +          std::bind(&TripletSelector::previousComboBoxItem, fontComboBox_));
    
    407
    +  connect(faceUpButton_   , &QToolButton::clicked, 
    
    408
    +          this, 
    
    409
    +          std::bind(&TripletSelector::previousComboBoxItem, faceComboBox_));
    
    410
    +  connect(niUpButton_     , &QToolButton::clicked, 
    
    411
    +          this, 
    
    412
    +          std::bind(&TripletSelector::previousComboBoxItem, niComboBox_));
    
    413
    +  connect(fontDownButton_ , &QToolButton::clicked, 
    
    414
    +          this, 
    
    415
    +          std::bind(&TripletSelector::nextComboBoxItem, fontComboBox_));
    
    416
    +  connect(faceDownButton_ , &QToolButton::clicked, 
    
    417
    +          this,
    
    418
    +          std::bind(&TripletSelector::nextComboBoxItem, faceComboBox_));
    
    419
    +  connect(niDownButton_   , &QToolButton::clicked, 
    
    420
    +          this, 
    
    421
    +          std::bind(&TripletSelector::nextComboBoxItem, niComboBox_));
    
    422
    +
    
    423
    +  connect(&engine_->fontFileManager(), &FontFileManager::currentFileChanged,
    
    424
    +          this, &TripletSelector::watchCurrentFont);
    
    425
    +}
    
    426
    +
    
    427
    +
    
    428
    +void
    
    429
    +TripletSelector::loadTriplet()
    
    430
    +{
    
    431
    +  // we do lazy computation of FT_Face objects
    
    432
    +
    
    433
    +  // TODO really?
    
    434
    +  auto fontIndex = fontComboBox_->currentIndex();
    
    435
    +  auto faceIndex = faceComboBox_->currentIndex();
    
    436
    +  auto instanceIndex = niComboBox_->currentIndex();
    
    437
    +
    
    438
    +  if (fontIndex >= 0 && fontIndex < engine_->numberOfOpenedFonts())
    
    439
    +  {
    
    440
    +    QFileInfo& fileInfo = engine_->fontFileManager()[fontIndex];
    
    441
    +    engine_->fontFileManager().updateWatching(fontIndex);
    
    442
    +
    
    443
    +    if (!fileInfo.exists())
    
    444
    +    {
    
    445
    +      // On Unix-like systems, the symlink's target gets opened; this
    
    446
    +      // implies that deletion of a symlink doesn't make `engine->loadFont'
    
    447
    +      // fail since it operates on a file handle pointing to the target.
    
    448
    +      // For this reason, we remove the font to enforce a reload.
    
    449
    +      engine_->removeFont(fontIndex, false);
    
    450
    +    }
    
    451
    +  }
    
    452
    +
    
    453
    +  engine_->loadFont(fontIndex, faceIndex, instanceIndex);
    
    454
    +  
    
    455
    +  // TODO: This may messes up with bitmap-only fonts.
    
    456
    +  if (!engine_->fontValid())
    
    457
    +  {
    
    458
    +    // there might be various reasons why the current
    
    459
    +    // (file, face, instance) triplet is invalid or missing;
    
    460
    +    // we thus start our timer to periodically test
    
    461
    +    // whether the font starts working
    
    462
    +    if (faceIndex >= 0 && faceIndex < engine_->numberOfOpenedFonts())
    
    463
    +      engine_->fontFileManager().timerStart();
    
    464
    +  }
    
    465
    +
    
    466
    +  emit tripletChanged();
    
    467
    +}
    
    468
    +
    
    469
    +
    
    470
    +void
    
    471
    +TripletSelector::nextComboBoxItem(QComboBox* c)
    
    472
    +{
    
    473
    +  if (c->currentIndex() < 0 || c->currentIndex() >= c->count() - 1)
    
    474
    +    return;
    
    475
    +  // No need to handle further steps, the event handler will take care of these
    
    476
    +  c->setCurrentIndex(c->currentIndex() + 1);
    
    477
    +}
    
    478
    +
    
    479
    +
    
    480
    +void
    
    481
    +TripletSelector::previousComboBoxItem(QComboBox* c)
    
    482
    +{
    
    483
    +  if (c->currentIndex() <= 0)
    
    484
    +    return;
    
    485
    +  // No need to handle further steps, the event handler will take care of these
    
    486
    +  c->setCurrentIndex(c->currentIndex() - 1);
    
    487
    +}
    
    488
    +
    
    489
    +
    
    490
    +// end of tripletselector.cpp

  • src/ftinspect/widgets/tripletselector.hpp
    1
    +// QPushButton.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include <vector>
    
    8
    +#include <QWidget>
    
    9
    +#include <QComboBox>
    
    10
    +#include <QPushButton>
    
    11
    +#include <QToolButton>
    
    12
    +#include <QBoxLayout>
    
    13
    +
    
    14
    +class Engine;
    
    15
    +class TripletSelector
    
    16
    +: public QWidget
    
    17
    +{
    
    18
    +  Q_OBJECT
    
    19
    +
    
    20
    +public:
    
    21
    +  TripletSelector(QWidget* parent,
    
    22
    +                  Engine* engine);
    
    23
    +  ~TripletSelector() override;
    
    24
    +
    
    25
    +  void repopulateFonts();
    
    26
    +  void closeCurrentFont();
    
    27
    +
    
    28
    +signals:
    
    29
    +  void tripletChanged();
    
    30
    +
    
    31
    +private:
    
    32
    +  Engine* engine_;
    
    33
    +
    
    34
    +  QComboBox* fontComboBox_;
    
    35
    +  QComboBox* faceComboBox_;
    
    36
    +  QComboBox* niComboBox_;
    
    37
    +
    
    38
    +  QToolButton* closeFontButton_;
    
    39
    +
    
    40
    +  QToolButton* fontUpButton_;
    
    41
    +  QToolButton* fontDownButton_;
    
    42
    +  QToolButton* faceUpButton_;
    
    43
    +  QToolButton* faceDownButton_;
    
    44
    +  QToolButton* niUpButton_;
    
    45
    +  QToolButton* niDownButton_;
    
    46
    +
    
    47
    +  QHBoxLayout* layout_;
    
    48
    +
    
    49
    +  void checkButtons();
    
    50
    +  void watchCurrentFont();
    
    51
    +
    
    52
    +  void createLayout();
    
    53
    +  void createConnections();
    
    54
    +
    
    55
    +  void repopulateFaces(bool fontSwitched = true);
    
    56
    +  void repopulateNamedInstances(bool fontSwitched = true);
    
    57
    +  void updateFont();
    
    58
    +  void updateFace();
    
    59
    +  void updateNI();
    
    60
    +  void loadTriplet();
    
    61
    +
    
    62
    +  static void nextComboBoxItem(QComboBox* c);
    
    63
    +  static void previousComboBoxItem(QComboBox* c);
    
    64
    +};
    
    65
    +
    
    66
    +
    
    67
    +// end of QPushButton.hpp


  • reply via email to

    [Prev in Thread] Current Thread [Next in Thread]