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-2] 8 commits: [ftinspec


From: Charlie Jiang (@cqjjjzr)
Subject: [Git][freetype/freetype-demos][gsoc-2022-chariri-2] 8 commits: [ftinspect] Add "Show Grid" check box.
Date: Fri, 15 Jul 2022 10:36:36 +0000

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

Commits:

  • 38f60d85
    by Charlie Jiang at 2022-07-14T16:31:43+08:00
    [ftinspect] Add "Show Grid" check box.
    
    * src/ftinspect/panels/singular.cpp, src/ftinspect/panels/singular.hpp:
      Add "Show Grid" check box, which uses `QGraphicsItem::setVisible`.
    
    * src/ftinspect/rendering/grid.cpp: Remove TODO that has been resolved.
    
  • 60bb6f09
    by Charlie Jiang at 2022-07-14T17:04:02+08:00
    [ftinspect] Fix build error on old FreeType verions.
    
    FreeType older than 2.12.0 don't have `FT_GLYPH_FORMAT_SVG`.
    
    * src/ftinspect/panels/singular.cpp: Add conditional compilation.
    
  • 6f5ac858
    by Charlie Jiang at 2022-07-14T17:28:47+08:00
    * src/ftinspect/engine/engine.cpp: Fix segfault on Linux.
    
    Honestly I have no idea how this should have been able to run on Windows.
    
  • a42eb7f9
    by Charlie Jiang at 2022-07-15T14:23:36+08:00
    [ftinspect] Fix grid background in dark mode.
    
    * src/ftinspect/panels/singular.cpp: Force white as the background color.
      Set overlay label's foreground color to the correct color.
    
  • 7b4fb4f7
    by Charlie Jiang at 2022-07-15T14:31:57+08:00
    [ftinspect] Rewrite the GUI layout of "Continuous View"
    
    We no longer use sub-tabs to switch between "All Glyphs", "Text String" or
    other modes, and use a combo box instead. This makes the two major options
    clear:
    
    - Render Mode: Normal, Fancy, Stroked etc...
    - Text Source: All Glyphs, Text String etc...
    
    Move most code in the original "All Glyphs" sub-tab to `ContinuousTab`, and
    add other options. However, they're not implemented yet.
    
    * src/ftinspect/panels/continuous.hpp, src/ftinspect/panels/continuous.cpp:
      As described.
    
    * src/ftinspect/rendering/glyphcontinuous.cpp,
      src/ftinspect/rendering/glyphcontinuous.hpp:
      Add new options as properties. Rename "Mode" to "Source", "SubMode" to
      "Mode".
    
  • 469443c4
    by Charlie Jiang at 2022-07-15T14:53:34+08:00
    [ftinspect] Rework on scroll tooltip of "Singular View"
    
    The overlay tooltip explaining scroll operations in the singular view is
    annoying and ugly. Move it into a small button on the right-bottom corner..
    Only show the tooltip when clicking the button.
    
    * src/ftinspect/panels/singular.cpp, src/ftinspect/panels/singular.hpp:
      As described.
    
  • a1c3e64a
    by Charlie Jiang at 2022-07-15T16:01:09+08:00
    [ftinspect] Move "waterfall" out as a separate option.
    
    "Waterfall" rendering is rather a pattern applied for the whole view instead
    of individual characters. Therefore it shouldn't be placed into "Render
    Mode" where Fancy/Stroked are placed.
    
    Also squeezes out some horizontal space by rewording labels.
    
    * src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
      As described.
    
    * src/ftinspect/rendering/glyphcontinuous.cpp:
      Make "waterfall" a separate property instead a value in the mode enum.
    
  • c09da8bc
    by Charlie Jiang at 2022-07-15T18:29:07+08:00
    [ftinspect] Let continuous view support non-outline glyphs.
    
    Integrate the rendering infrastructure we built previously into the
    `GlyphContinuous`.
    
    TODO: Optimize: Cache `QImage`s because they're expensive to create.
    
    * src/ftinspect/rendering/glyphcontinuous.cpp,
      src/ftinspect/rendering/glyphcontinuous.hpp:
      As described, integrate rendering infrastructures from `Engine`.
      Add better documentation for FreeType objects stored in the class.
      Removed `cloneOutline` since you should never clone an outline alone.
      Renamed some functions.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
      Split `convertBitmapToQImage` into `convertGlyphToQImage` and
      `convertBitmapToQImage`, add `computeGlyphOffset` and rename
      `glyphToBitmap` to follow the style `convertXXX`.
    
    * src/ftinspect/rendering/glyphbitmap.cpp: Update renamed function ref.
    
    * src/ftinspect/rendering/renderutils.cpp,
      src/ftinspect/rendering/renderutils.hpp: Add `cloneBitmap`.
    

12 changed files:

Changes:

  • src/ftinspect/engine/engine.cpp
    ... ... @@ -384,7 +384,10 @@ Engine::glyphName(int index)
    384 384
       if (index < 0)
    
    385 385
         throw std::runtime_error("Invalid glyph index");
    
    386 386
     
    
    387
    -   if (!FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
    
    387
    +  if (!ftSize_)
    
    388
    +    return "";
    
    389
    +
    
    390
    +  if (!FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
    
    388 391
         return name;
    
    389 392
     
    
    390 393
       if (ftSize_ && FT_HAS_GLYPH_NAMES(ftSize_->face))
    
    ... ... @@ -409,6 +412,9 @@ Engine::loadGlyph(int glyphIndex)
    409 412
       if (glyphIndex < 0)
    
    410 413
         throw std::runtime_error("Invalid glyph index");
    
    411 414
     
    
    415
    +  if (curNumGlyphs_ <= 0)
    
    416
    +    return NULL;
    
    417
    +
    
    412 418
       FT_Glyph glyph;
    
    413 419
     
    
    414 420
       // the `scaler' object is set up by the
    
    ... ... @@ -447,7 +453,7 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex)
    447 453
     
    
    448 454
     
    
    449 455
     bool
    
    450
    -Engine::glyphToBitmap(FT_Glyph src,
    
    456
    +Engine::convertGlyphToBitmapGlyph(FT_Glyph src,
    
    451 457
                           FT_Glyph* out)
    
    452 458
     {
    
    453 459
       if (src->format == FT_GLYPH_FORMAT_BITMAP)
    
    ... ... @@ -733,16 +739,11 @@ convertLCDVToARGB(FT_Bitmap& bitmap,
    733 739
     
    
    734 740
     
    
    735 741
     QImage*
    
    736
    -Engine::convertBitmapToQImage(FT_Glyph src,
    
    737
    -                              QRect* outRect)
    
    742
    +Engine::convertBitmapToQImage(FT_Bitmap* src)
    
    738 743
     {
    
    739 744
       QImage* result = NULL;
    
    740
    -  FT_BitmapGlyph bitmapGlyph;
    
    741
    -  bool ownBitmapGlyph
    
    742
    -    = glyphToBitmap(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
    
    743
    -  if (!bitmapGlyph)
    
    744
    -    return result;
    
    745
    -  auto& bmap = bitmapGlyph->bitmap;
    
    745
    +  
    
    746
    +  auto& bmap = *src;
    
    746 747
       bool ownBitmap = false;
    
    747 748
     
    
    748 749
       int width = bmap.width;
    
    ... ... @@ -763,14 +764,6 @@ Engine::convertBitmapToQImage(FT_Glyph src,
    763 764
       else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
    
    764 765
         height /= 3;
    
    765 766
     
    
    766
    -  if (outRect)
    
    767
    -  {
    
    768
    -    outRect->setLeft(bitmapGlyph->left);
    
    769
    -    outRect->setTop(-bitmapGlyph->top);
    
    770
    -    outRect->setWidth(width);
    
    771
    -    outRect->setHeight(height);
    
    772
    -  }
    
    773
    -
    
    774 767
       switch (bmap.pixel_mode)
    
    775 768
       {
    
    776 769
       case FT_PIXEL_MODE_MONO:
    
    ... ... @@ -821,8 +814,6 @@ Engine::convertBitmapToQImage(FT_Glyph src,
    821 814
       }
    
    822 815
     
    
    823 816
     cleanup:
    
    824
    -  if (ownBitmapGlyph)
    
    825
    -    FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
    
    826 817
       if (ownBitmap)
    
    827 818
         FT_Bitmap_Done(library_, &bmap);
    
    828 819
     
    
    ... ... @@ -830,6 +821,56 @@ cleanup:
    830 821
     }
    
    831 822
     
    
    832 823
     
    
    824
    +QImage*
    
    825
    +Engine::convertGlyphToQImage(FT_Glyph src, QRect* outRect)
    
    826
    +{
    
    827
    +  FT_BitmapGlyph bitmapGlyph;
    
    828
    +  bool ownBitmapGlyph
    
    829
    +    = convertGlyphToBitmapGlyph(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
    
    830
    +  if (!bitmapGlyph)
    
    831
    +    return NULL;
    
    832
    +
    
    833
    +  auto result = convertBitmapToQImage(&bitmapGlyph->bitmap);
    
    834
    +
    
    835
    +  if (result && outRect)
    
    836
    +  {
    
    837
    +    outRect->setLeft(bitmapGlyph->left);
    
    838
    +    outRect->setTop(-bitmapGlyph->top);
    
    839
    +    outRect->setWidth(bitmapGlyph->bitmap.width);
    
    840
    +    outRect->setHeight(bitmapGlyph->bitmap.rows);
    
    841
    +  }
    
    842
    +
    
    843
    +  if (ownBitmapGlyph)
    
    844
    +    FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
    
    845
    +
    
    846
    +  return result;
    
    847
    +}
    
    848
    +
    
    849
    +
    
    850
    +QPoint
    
    851
    +Engine::computeGlyphOffset(FT_Glyph glyph)
    
    852
    +{
    
    853
    +  if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
    
    854
    +  {
    
    855
    +    FT_BBox cbox;
    
    856
    +    FT_Outline_Get_CBox(&reinterpret_cast<FT_OutlineGlyph>(glyph)->outline, 
    
    857
    +                        &cbox);
    
    858
    +    cbox.xMin &= ~63;
    
    859
    +    cbox.yMin &= ~63;
    
    860
    +    cbox.xMax = (cbox.xMax + 63) & ~63;
    
    861
    +    cbox.yMax = (cbox.yMax + 63) & ~63;
    
    862
    +    return { cbox.xMin / 64, -cbox.yMax / 64 };
    
    863
    +  }
    
    864
    +  if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
    
    865
    +  {
    
    866
    +    auto bg = reinterpret_cast<FT_BitmapGlyph>(glyph);
    
    867
    +    return { bg->left, -bg->top };
    
    868
    +  }
    
    869
    +
    
    870
    +  return {};
    
    871
    +}
    
    872
    +
    
    873
    +
    
    833 874
     QHash<FT_Glyph_Format, QString> glyphFormatNamesCache;
    
    834 875
     QHash<FT_Glyph_Format, QString>&
    
    835 876
     glyphFormatNames()
    
    ... ... @@ -841,7 +882,9 @@ glyphFormatNames()
    841 882
         glyphFormatNamesCache[FT_GLYPH_FORMAT_BITMAP] = "Bitmap";
    
    842 883
         glyphFormatNamesCache[FT_GLYPH_FORMAT_OUTLINE] = "Outline";
    
    843 884
         glyphFormatNamesCache[FT_GLYPH_FORMAT_PLOTTER] = "Plotter";
    
    885
    +#if FREETYPE_MINOR >= 12
    
    844 886
         glyphFormatNamesCache[FT_GLYPH_FORMAT_SVG] = "SVG";
    
    887
    +#endif
    
    845 888
       }
    
    846 889
       return glyphFormatNamesCache;
    
    847 890
     }
    

  • src/ftinspect/engine/engine.hpp
    ... ... @@ -105,9 +105,11 @@ public:
    105 105
     
    
    106 106
       // Return `true` if you need to free `out`
    
    107 107
       // `out` will be set to NULL in cases of error
    
    108
    -  bool glyphToBitmap(FT_Glyph src, FT_Glyph* out);
    
    108
    +  bool convertGlyphToBitmapGlyph(FT_Glyph src, FT_Glyph* out);
    
    109 109
       FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
    
    110
    -  QImage* convertBitmapToQImage(FT_Glyph src, QRect* outRect);
    
    110
    +  QImage* convertBitmapToQImage(FT_Bitmap* src);
    
    111
    +  QImage* convertGlyphToQImage(FT_Glyph src, QRect* outRect);
    
    112
    +  QPoint computeGlyphOffset(FT_Glyph glyph);
    
    111 113
     
    
    112 114
       // reload current triplet, but with updated settings, useful for updating
    
    113 115
       // `ftSize_` only
    

  • src/ftinspect/panels/continuous.cpp
    ... ... @@ -13,6 +13,14 @@ ContinuousTab::ContinuousTab(QWidget* parent,
    13 13
     : QWidget(parent), engine_(engine)
    
    14 14
     {
    
    15 15
       createLayout();
    
    16
    +
    
    17
    +  std::vector<CharMapInfo> tempCharMaps;
    
    18
    +  setCharMaps(tempCharMaps); // pass in an empty one
    
    19
    +
    
    20
    +  checkMode();
    
    21
    +  checkSource();
    
    22
    +  setDefaults();
    
    23
    +
    
    16 24
       createConnections();
    
    17 25
     }
    
    18 26
     
    
    ... ... @@ -22,7 +30,7 @@ ContinuousTab::repaintGlyph()
    22 30
     {
    
    23 31
       sizeSelector_->applyToEngine(engine_);
    
    24 32
       
    
    25
    -  updateFromCurrentSubTab();
    
    33
    +  syncSettings();
    
    26 34
       canvas_->repaint();
    
    27 35
     }
    
    28 36
     
    
    ... ... @@ -31,181 +39,36 @@ void
    31 39
     ContinuousTab::reloadFont()
    
    32 40
     {
    
    33 41
       currentGlyphCount_ = engine_->currentFontNumberOfGlyphs();
    
    34
    -  updateCurrentSubTab();
    
    42
    +  setGlyphCount(qBound(0, currentGlyphCount_, INT_MAX));
    
    43
    +  setCharMaps(engine_->currentFontCharMaps());
    
    35 44
       repaintGlyph();
    
    36 45
     }
    
    37 46
     
    
    38 47
     
    
    39 48
     void
    
    40
    -ContinuousTab::changeTab()
    
    41
    -{
    
    42
    -  updateCurrentSubTab();
    
    43
    -  repaintGlyph();
    
    44
    -}
    
    45
    -
    
    46
    -
    
    47
    -void
    
    48
    -ContinuousTab::wheelNavigate(int steps)
    
    49
    -{
    
    50
    -  if (tabWidget_->currentIndex() == AllGlyphs)
    
    51
    -    allGlyphsTab_->setGlyphBeginindex(allGlyphsTab_->glyphBeginindex()
    
    52
    -                                      + steps);
    
    53
    -}
    
    54
    -
    
    55
    -
    
    56
    -void
    
    57
    -ContinuousTab::wheelResize(int steps)
    
    58
    -{
    
    59
    -  sizeSelector_->handleWheelResizeBySteps(steps);
    
    60
    -}
    
    61
    -
    
    62
    -
    
    63
    -void
    
    64
    -ContinuousTab::createLayout()
    
    65
    -{
    
    66
    -  canvas_ = new GlyphContinuous(this, engine_);
    
    67
    -  sizeSelector_ = new FontSizeSelector(this);
    
    68
    -  allGlyphsTab_ = new ContinousAllGlyphsTab(this);
    
    69
    -
    
    70
    -  tabWidget_ = new QTabWidget(this);
    
    71
    -  tabWidget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    72
    -  // Must be in sync with `Tabs` enum.
    
    73
    -  tabWidget_->addTab(allGlyphsTab_, tr("All Glyphs"));
    
    74
    -
    
    75
    -  mainLayout_ = new QVBoxLayout;
    
    76
    -  mainLayout_->addWidget(canvas_);
    
    77
    -  mainLayout_->addWidget(sizeSelector_);
    
    78
    -  mainLayout_->addWidget(tabWidget_);
    
    79
    -
    
    80
    -  setLayout(mainLayout_);
    
    81
    -}
    
    82
    -
    
    83
    -
    
    84
    -void
    
    85
    -ContinuousTab::createConnections()
    
    86
    -{
    
    87
    -  connect(tabWidget_, &QTabWidget::currentChanged,
    
    88
    -          this, &ContinuousTab::changeTab);
    
    89
    -
    
    90
    -  connect(allGlyphsTab_, &ContinousAllGlyphsTab::changed, 
    
    91
    -          this, &ContinuousTab::repaintGlyph);
    
    92
    -
    
    93
    -  connect(sizeSelector_, &FontSizeSelector::valueChanged,
    
    94
    -          this, &ContinuousTab::repaintGlyph);
    
    95
    -
    
    96
    -  connect(canvas_, &GlyphContinuous::wheelResize, 
    
    97
    -          this, &ContinuousTab::wheelResize);
    
    98
    -  connect(canvas_, &GlyphContinuous::wheelNavigate, 
    
    99
    -          this, &ContinuousTab::wheelNavigate);
    
    100
    -  connect(canvas_, &GlyphContinuous::displayingCountUpdated, 
    
    101
    -          allGlyphsTab_, &ContinousAllGlyphsTab::setDisplayingCount);
    
    102
    -}
    
    103
    -
    
    104
    -
    
    105
    -void
    
    106
    -ContinuousTab::updateCurrentSubTab()
    
    49
    +ContinuousTab::syncSettings()
    
    107 50
     {
    
    108
    -  switch (tabWidget_->currentIndex())
    
    109
    -  {
    
    110
    -  case AllGlyphs:
    
    111
    -    allGlyphsTab_->setGlyphCount(qBound(0, 
    
    112
    -                                        currentGlyphCount_,
    
    113
    -                                        INT_MAX));
    
    114
    -    allGlyphsTab_->setCharMaps(engine_->currentFontCharMaps());
    
    115
    -    break;
    
    116
    -  }
    
    117
    -}
    
    118
    -
    
    119
    -
    
    120
    -void
    
    121
    -ContinuousTab::updateFromCurrentSubTab()
    
    122
    -{
    
    123
    -  switch (tabWidget_->currentIndex())
    
    124
    -  {
    
    125
    -  case AllGlyphs:
    
    126
    -    canvas_->setMode(GlyphContinuous::AllGlyphs);
    
    127
    -    canvas_->setSubModeAllGlyphs(allGlyphsTab_->subMode());
    
    128
    -    // Begin index is selected from All Glyphs subtab,
    
    129
    -    // and Limit index is calculated by All Glyphs subtab
    
    130
    -    canvas_->setBeginIndex(allGlyphsTab_->glyphBeginindex());
    
    131
    -    canvas_->setLimitIndex(allGlyphsTab_->glyphLimitIndex());
    
    132
    -    canvas_->setCharMapIndex(allGlyphsTab_->charMapIndex());
    
    133
    -
    
    134
    -    canvas_->setFancyParams(allGlyphsTab_->xEmboldening(),
    
    135
    -                            allGlyphsTab_->yEmboldening(),
    
    136
    -                            allGlyphsTab_->slanting());
    
    137
    -    canvas_->setStrokeRadius(allGlyphsTab_->strokeRadius());
    
    138
    -    break;
    
    139
    -  }
    
    140
    -}
    
    141
    -
    
    142
    -
    
    143
    -ContinousAllGlyphsTab::ContinousAllGlyphsTab(QWidget* parent)
    
    144
    -: QWidget(parent)
    
    145
    -{
    
    146
    -  createLayout();
    
    147
    -
    
    148
    -  std::vector<CharMapInfo> tempCharMaps;
    
    149
    -  setCharMaps(tempCharMaps); // pass in an empty one
    
    150
    -
    
    151
    -  checkSubMode();
    
    152
    -  setDefaults();
    
    153
    -  createConnections();
    
    154
    -}
    
    155
    -
    
    156
    -
    
    157
    -int
    
    158
    -ContinousAllGlyphsTab::glyphBeginindex()
    
    159
    -{
    
    160
    -  return indexSelector_->currentIndex();
    
    51
    +  auto mode = static_cast<GlyphContinuous::Mode>(modeSelector_->currentIndex());
    
    52
    +  auto src
    
    53
    +    = static_cast<GlyphContinuous::Source>(sourceSelector_->currentIndex());
    
    54
    +  canvas_->setMode(mode);
    
    55
    +  canvas_->setSource(src);
    
    56
    +  canvas_->setBeginIndex(indexSelector_->currentIndex());
    
    57
    +  canvas_->setLimitIndex(glyphLimitIndex_);
    
    58
    +  canvas_->setCharMapIndex(charMapIndex()); // Not directly from the combo box
    
    59
    +
    
    60
    +  canvas_->setFancyParams(xEmboldeningSpinBox_->value(),
    
    61
    +                          yEmboldeningSpinBox_->value(),
    
    62
    +                          slantSpinBox_->value());
    
    63
    +  canvas_->setStrokeRadius(strokeRadiusSpinBox_->value());
    
    64
    +  canvas_->setRotation(rotationSpinBox_->value());
    
    65
    +  canvas_->setWaterfall(waterfallCheckBox_->isChecked());
    
    66
    +  canvas_->setVertical(verticalCheckBox_->isChecked());
    
    161 67
     }
    
    162 68
     
    
    163 69
     
    
    164 70
     int
    
    165
    -ContinousAllGlyphsTab::glyphLimitIndex()
    
    166
    -{
    
    167
    -  return glyphLimitIndex_;
    
    168
    -}
    
    169
    -
    
    170
    -
    
    171
    -GlyphContinuous::SubModeAllGlyphs
    
    172
    -ContinousAllGlyphsTab::subMode()
    
    173
    -{
    
    174
    -  return static_cast<GlyphContinuous::SubModeAllGlyphs>(
    
    175
    -           modeSelector_->currentIndex());
    
    176
    -}
    
    177
    -
    
    178
    -
    
    179
    -double
    
    180
    -ContinousAllGlyphsTab::xEmboldening()
    
    181
    -{
    
    182
    -  return xEmboldeningSpinBox_->value();
    
    183
    -}
    
    184
    -
    
    185
    -
    
    186
    -double
    
    187
    -ContinousAllGlyphsTab::yEmboldening()
    
    188
    -{
    
    189
    -  return yEmboldeningSpinBox_->value();
    
    190
    -}
    
    191
    -
    
    192
    -
    
    193
    -double
    
    194
    -ContinousAllGlyphsTab::slanting()
    
    195
    -{
    
    196
    -  return slantSpinBox_->value();
    
    197
    -}
    
    198
    -
    
    199
    -
    
    200
    -double
    
    201
    -ContinousAllGlyphsTab::strokeRadius()
    
    202
    -{
    
    203
    -  return strokeRadiusSpinBox_->value();
    
    204
    -}
    
    205
    -
    
    206
    -
    
    207
    -int
    
    208
    -ContinousAllGlyphsTab::charMapIndex()
    
    71
    +ContinuousTab::charMapIndex()
    
    209 72
     {
    
    210 73
       auto index = charMapSelector_->currentIndex() - 1;
    
    211 74
       if (index <= -1)
    
    ... ... @@ -217,30 +80,30 @@ ContinousAllGlyphsTab::charMapIndex()
    217 80
     
    
    218 81
     
    
    219 82
     void
    
    220
    -ContinousAllGlyphsTab::setGlyphBeginindex(int index)
    
    83
    +ContinuousTab::setGlyphCount(int count)
    
    221 84
     {
    
    222
    -  indexSelector_->setCurrentIndex(index);
    
    85
    +  currentGlyphCount_ = count;
    
    86
    +  updateLimitIndex();
    
    223 87
     }
    
    224 88
     
    
    225 89
     
    
    226 90
     void
    
    227
    -ContinousAllGlyphsTab::setGlyphCount(int count)
    
    91
    +ContinuousTab::setDisplayingCount(int count)
    
    228 92
     {
    
    229
    -  currentGlyphCount_ = count;
    
    230
    -  updateLimitIndex();
    
    93
    +  indexSelector_->setShowingCount(count);
    
    231 94
     }
    
    232 95
     
    
    233 96
     
    
    234 97
     void
    
    235
    -ContinousAllGlyphsTab::setDisplayingCount(int count)
    
    98
    +ContinuousTab::setGlyphBeginindex(int index)
    
    236 99
     {
    
    237
    -  indexSelector_->setShowingCount(count);
    
    100
    +  indexSelector_->setCurrentIndex(index);
    
    238 101
     }
    
    239 102
     
    
    240 103
     
    
    241 104
     #define EncodingRole (Qt::UserRole + 10)
    
    242 105
     void
    
    243
    -ContinousAllGlyphsTab::setCharMaps(std::vector<CharMapInfo>& charMaps)
    
    106
    +ContinuousTab::setCharMaps(std::vector<CharMapInfo>& charMaps)
    
    244 107
     {
    
    245 108
       charMaps_ = charMaps;
    
    246 109
       int oldIndex = charMapSelector_->currentIndex();
    
    ... ... @@ -287,7 +150,7 @@ ContinousAllGlyphsTab::setCharMaps(std::vector<CharMapInfo>& charMaps)
    287 150
     
    
    288 151
     
    
    289 152
     void
    
    290
    -ContinousAllGlyphsTab::updateLimitIndex()
    
    153
    +ContinuousTab::updateLimitIndex()
    
    291 154
     {
    
    292 155
       if (charMapSelector_->currentIndex() <= 0)
    
    293 156
         glyphLimitIndex_ = currentGlyphCount_;
    
    ... ... @@ -299,49 +162,127 @@ ContinousAllGlyphsTab::updateLimitIndex()
    299 162
     
    
    300 163
     
    
    301 164
     void
    
    302
    -ContinousAllGlyphsTab::checkSubMode()
    
    165
    +ContinuousTab::checkMode()
    
    303 166
     {
    
    304
    -  auto isFancy = subMode() == GlyphContinuous::AG_Fancy;
    
    305
    -  auto isStroked = subMode() == GlyphContinuous::AG_Stroked;
    
    167
    +  auto isFancy = modeSelector_->currentIndex() == GlyphContinuous::M_Fancy;
    
    168
    +  auto isStroked = modeSelector_->currentIndex() == GlyphContinuous::M_Stroked;
    
    306 169
       xEmboldeningSpinBox_->setEnabled(isFancy);
    
    307 170
       yEmboldeningSpinBox_->setEnabled(isFancy);
    
    308 171
       slantSpinBox_->setEnabled(isFancy);
    
    309 172
       strokeRadiusSpinBox_->setEnabled(isStroked);
    
    310 173
     
    
    311
    -  emit changed();
    
    174
    +  repaintGlyph();
    
    312 175
     }
    
    313 176
     
    
    314 177
     
    
    315 178
     void
    
    316
    -ContinousAllGlyphsTab::createLayout()
    
    179
    +ContinuousTab::checkSource()
    
    317 180
     {
    
    181
    +  auto src
    
    182
    +      = static_cast<GlyphContinuous::Source>(sourceSelector_->currentIndex());
    
    183
    +  auto isText = src == GlyphContinuous::SRC_TextString
    
    184
    +                || src == GlyphContinuous::SRC_TextStringRepeated;
    
    185
    +  indexSelector_->setEnabled(src == GlyphContinuous::SRC_AllGlyphs);
    
    186
    +  sourceTextEdit_->setEnabled(isText);
    
    187
    +  verticalCheckBox_->setEnabled(isText);
    
    188
    +
    
    189
    +  repaintGlyph();
    
    190
    +}
    
    191
    +
    
    192
    +
    
    193
    +void
    
    194
    +ContinuousTab::charMapChanged()
    
    195
    +{
    
    196
    +  int newIndex = charMapSelector_->currentIndex();
    
    197
    +  if (newIndex != lastCharMapIndex_)
    
    198
    +  {
    
    199
    +    if (newIndex <= 0
    
    200
    +        || charMaps_.size() <= static_cast<unsigned>(newIndex - 1))
    
    201
    +      setGlyphBeginindex(0);
    
    202
    +    else if (charMaps_[newIndex - 1].maxIndex <= 20)
    
    203
    +      setGlyphBeginindex(charMaps_[newIndex - 1].maxIndex - 1);
    
    204
    +    else
    
    205
    +      setGlyphBeginindex(0x20);
    
    206
    +  }
    
    207
    +  updateLimitIndex();
    
    208
    +
    
    209
    +  repaintGlyph();
    
    210
    +
    
    211
    +  lastCharMapIndex_ = newIndex;
    
    212
    +}
    
    213
    +
    
    214
    +
    
    215
    +void
    
    216
    +ContinuousTab::sourceTextChanged()
    
    217
    +{
    
    218
    +  canvas_->setSourceText(sourceTextEdit_->toPlainText());
    
    219
    +  repaintGlyph();
    
    220
    +}
    
    221
    +
    
    222
    +
    
    223
    +void
    
    224
    +ContinuousTab::wheelNavigate(int steps)
    
    225
    +{
    
    226
    +  if (sourceSelector_->currentIndex() == GlyphContinuous::SRC_AllGlyphs)
    
    227
    +    setGlyphBeginindex(indexSelector_->currentIndex() + steps);
    
    228
    +}
    
    229
    +
    
    230
    +
    
    231
    +void
    
    232
    +ContinuousTab::wheelResize(int steps)
    
    233
    +{
    
    234
    +  sizeSelector_->handleWheelResizeBySteps(steps);
    
    235
    +}
    
    236
    +
    
    237
    +
    
    238
    +void
    
    239
    +ContinuousTab::createLayout()
    
    240
    +{
    
    241
    +  canvas_ = new GlyphContinuous(this, engine_);
    
    242
    +  sizeSelector_ = new FontSizeSelector(this);
    
    243
    +
    
    318 244
       indexSelector_ = new GlyphIndexSelector(this);
    
    319 245
       indexSelector_->setSingleMode(false);
    
    320 246
       indexSelector_->setNumberRenderer([this](int index)
    
    321 247
                                         { return formatIndex(index); });
    
    248
    +  sourceTextEdit_ = new QPlainTextEdit(
    
    249
    +      tr("The quick brown fox jumps over the lazy dog."), this);
    
    322 250
     
    
    323 251
       modeSelector_ = new QComboBox(this);
    
    324 252
       charMapSelector_ = new QComboBox(this);
    
    253
    +  sourceSelector_ = new QComboBox(this);
    
    325 254
     
    
    326 255
       // Note: in sync with the enum!!
    
    327
    -  modeSelector_->insertItem(GlyphContinuous::AG_AllGlyphs, tr("All Glyphs"));
    
    328
    -  modeSelector_->insertItem(GlyphContinuous::AG_Fancy, 
    
    329
    -                            tr("Fancy (Embolding & Slanting)"));
    
    330
    -  modeSelector_->insertItem(GlyphContinuous::AG_Stroked, tr("Stroked"));
    
    331
    -  modeSelector_->insertItem(GlyphContinuous::AG_Waterfall, tr("Waterfall"));
    
    332
    -  modeSelector_->setCurrentIndex(GlyphContinuous::AG_AllGlyphs);
    
    256
    +  modeSelector_->insertItem(GlyphContinuous::M_Normal, tr("Normal"));
    
    257
    +  modeSelector_->insertItem(GlyphContinuous::M_Fancy, tr("Fancy"));
    
    258
    +  modeSelector_->insertItem(GlyphContinuous::M_Stroked, tr("Stroked"));
    
    259
    +  modeSelector_->setCurrentIndex(GlyphContinuous::M_Normal);
    
    260
    +
    
    261
    +  // Note: in sync with the enum!!
    
    262
    +  sourceSelector_->insertItem(GlyphContinuous::SRC_AllGlyphs,
    
    263
    +                              tr("All Glyphs"));
    
    264
    +  sourceSelector_->insertItem(GlyphContinuous::SRC_TextString, 
    
    265
    +                              tr("Text String"));
    
    266
    +  sourceSelector_->insertItem(GlyphContinuous::SRC_TextStringRepeated,
    
    267
    +                              tr("Text String (Repeated)"));
    
    268
    +
    
    269
    +  verticalCheckBox_ = new QCheckBox(tr("Vertical Layout"), this);
    
    270
    +  waterfallCheckBox_ = new QCheckBox(tr("Waterfall"), this);
    
    333 271
     
    
    334 272
       modeLabel_ = new QLabel(tr("Mode:"), this);
    
    273
    +  sourceLabel_ = new QLabel(tr("Text Source:"), this);
    
    335 274
       charMapLabel_ = new QLabel(tr("Char Map:"), this);
    
    336
    -  xEmboldeningLabel_ = new QLabel(tr("Hori. Embolding:"), this);
    
    337
    -  yEmboldeningLabel_ = new QLabel(tr("Vert. Embolding:"), this);
    
    275
    +  xEmboldeningLabel_ = new QLabel(tr("Horz. Emb.:"), this);
    
    276
    +  yEmboldeningLabel_ = new QLabel(tr("Vert. Emb.:"), this);
    
    338 277
       slantLabel_ = new QLabel(tr("Slanting:"), this);
    
    339 278
       strokeRadiusLabel_ = new QLabel(tr("Stroke Radius:"), this);
    
    279
    +  rotationLabel_ = new QLabel(tr("Rotation:"), this);
    
    340 280
     
    
    341 281
       xEmboldeningSpinBox_ = new QDoubleSpinBox(this);
    
    342 282
       yEmboldeningSpinBox_ = new QDoubleSpinBox(this);
    
    343 283
       slantSpinBox_ = new QDoubleSpinBox(this);
    
    344 284
       strokeRadiusSpinBox_ = new QDoubleSpinBox(this);
    
    285
    +  rotationSpinBox_ = new QDoubleSpinBox(this);
    
    345 286
     
    
    346 287
       xEmboldeningSpinBox_->setSingleStep(0.005);
    
    347 288
       xEmboldeningSpinBox_->setMinimum(-0.1);
    
    ... ... @@ -355,93 +296,111 @@ ContinousAllGlyphsTab::createLayout()
    355 296
       strokeRadiusSpinBox_->setSingleStep(0.005);
    
    356 297
       strokeRadiusSpinBox_->setMinimum(0);
    
    357 298
       strokeRadiusSpinBox_->setMaximum(0.05);
    
    299
    +  rotationSpinBox_->setSingleStep(5);
    
    300
    +  rotationSpinBox_->setMinimum(-180);
    
    301
    +  rotationSpinBox_->setMaximum(180);
    
    302
    +
    
    303
    +  bottomLayout_ = new QGridLayout;
    
    304
    +  bottomLayout_->addWidget(sourceLabel_, 0, 0);
    
    305
    +  bottomLayout_->addWidget(modeLabel_, 1, 0);
    
    306
    +  bottomLayout_->addWidget(charMapLabel_, 2, 0);
    
    307
    +  bottomLayout_->addWidget(sourceSelector_, 0, 1);
    
    308
    +  bottomLayout_->addWidget(modeSelector_, 1, 1);
    
    309
    +  bottomLayout_->addWidget(charMapSelector_, 2, 1);
    
    310
    +
    
    311
    +  bottomLayout_->addWidget(xEmboldeningLabel_, 1, 2);
    
    312
    +  bottomLayout_->addWidget(yEmboldeningLabel_, 2, 2);
    
    313
    +  bottomLayout_->addWidget(slantLabel_, 3, 2);
    
    314
    +  bottomLayout_->addWidget(strokeRadiusLabel_, 3, 0);
    
    315
    +  bottomLayout_->addWidget(rotationLabel_, 0, 2);
    
    316
    +
    
    317
    +  bottomLayout_->addWidget(xEmboldeningSpinBox_, 1, 3);
    
    318
    +  bottomLayout_->addWidget(yEmboldeningSpinBox_, 2, 3);
    
    319
    +  bottomLayout_->addWidget(slantSpinBox_, 3, 3);
    
    320
    +  bottomLayout_->addWidget(strokeRadiusSpinBox_, 3, 1);
    
    321
    +  bottomLayout_->addWidget(rotationSpinBox_, 0, 3);
    
    322
    +
    
    323
    +  bottomLayout_->addWidget(indexSelector_, 0, 4, 1, 1);
    
    324
    +  bottomLayout_->addWidget(sourceTextEdit_, 1, 4, 3, 3);
    
    325
    +  bottomLayout_->addWidget(waterfallCheckBox_, 0, 5);
    
    326
    +  bottomLayout_->addWidget(verticalCheckBox_, 0, 6);
    
    327
    +
    
    328
    +  bottomLayout_->setColumnStretch(4, 1);
    
    329
    +
    
    330
    +  mainLayout_ = new QVBoxLayout;
    
    331
    +  mainLayout_->addWidget(canvas_);
    
    332
    +  mainLayout_->addWidget(sizeSelector_);
    
    333
    +  mainLayout_->addLayout(bottomLayout_);
    
    358 334
     
    
    359
    -  layout_ = new QGridLayout;
    
    360
    -  layout_->addWidget(indexSelector_, 0, 0, 1, 2);
    
    361
    -  layout_->addWidget(modeLabel_, 1, 0);
    
    362
    -  layout_->addWidget(charMapLabel_, 2, 0);
    
    363
    -  layout_->addWidget(modeSelector_, 1, 1);
    
    364
    -  layout_->addWidget(charMapSelector_, 2, 1);
    
    365
    -
    
    366
    -  layout_->addWidget(xEmboldeningLabel_, 1, 2);
    
    367
    -  layout_->addWidget(yEmboldeningLabel_, 2, 2);
    
    368
    -  layout_->addWidget(slantLabel_, 3, 2);
    
    369
    -  layout_->addWidget(strokeRadiusLabel_, 3, 0);
    
    370
    -  layout_->addWidget(xEmboldeningSpinBox_, 1, 3);
    
    371
    -  layout_->addWidget(yEmboldeningSpinBox_, 2, 3);
    
    372
    -  layout_->addWidget(slantSpinBox_, 3, 3);
    
    373
    -  layout_->addWidget(strokeRadiusSpinBox_, 3, 1);
    
    374
    -
    
    375
    -  layout_->setColumnStretch(1, 1);
    
    376
    -  layout_->setColumnStretch(3, 1);
    
    377
    -
    
    378
    -  setLayout(layout_);
    
    335
    +  setLayout(mainLayout_);
    
    379 336
     }
    
    380 337
     
    
    338
    +
    
    381 339
     void
    
    382
    -ContinousAllGlyphsTab::createConnections()
    
    340
    +ContinuousTab::createConnections()
    
    383 341
     {
    
    342
    +  connect(sizeSelector_, &FontSizeSelector::valueChanged,
    
    343
    +          this, &ContinuousTab::repaintGlyph);
    
    344
    +
    
    345
    +  connect(canvas_, &GlyphContinuous::wheelResize, 
    
    346
    +          this, &ContinuousTab::wheelResize);
    
    347
    +  connect(canvas_, &GlyphContinuous::wheelNavigate, 
    
    348
    +          this, &ContinuousTab::wheelNavigate);
    
    349
    +  connect(canvas_, &GlyphContinuous::displayingCountUpdated, 
    
    350
    +          this, &ContinuousTab::setDisplayingCount);
    
    351
    +
    
    384 352
       connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
    
    385
    -          this, &ContinousAllGlyphsTab::changed);
    
    353
    +          this, &ContinuousTab::repaintGlyph);
    
    386 354
       connect(modeSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    387
    -          this, &ContinousAllGlyphsTab::checkSubMode);
    
    355
    +          this, &ContinuousTab::checkMode);
    
    388 356
       connect(charMapSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    389
    -          this, &ContinousAllGlyphsTab::charMapChanged);
    
    357
    +          this, &ContinuousTab::charMapChanged);
    
    358
    +  connect(sourceSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    359
    +          this, &ContinuousTab::checkSource);
    
    390 360
     
    
    391 361
       connect(xEmboldeningSpinBox_, 
    
    392 362
               QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    393
    -          this, &ContinousAllGlyphsTab::changed);
    
    363
    +          this, &ContinuousTab::repaintGlyph);
    
    394 364
       connect(yEmboldeningSpinBox_, 
    
    395 365
               QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    396
    -          this, &ContinousAllGlyphsTab::changed);
    
    366
    +          this, &ContinuousTab::repaintGlyph);
    
    397 367
       connect(slantSpinBox_, 
    
    398 368
               QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    399
    -          this, &ContinousAllGlyphsTab::changed);
    
    369
    +          this, &ContinuousTab::repaintGlyph);
    
    400 370
       connect(strokeRadiusSpinBox_, 
    
    401 371
               QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    402
    -          this, &ContinousAllGlyphsTab::changed);
    
    403
    -}
    
    404
    -
    
    405
    -
    
    406
    -QString
    
    407
    -ContinousAllGlyphsTab::formatIndex(int index)
    
    408
    -{
    
    409
    -  if (charMapSelector_->currentIndex() <= 0) // glyph order
    
    410
    -    return QString::number(index);
    
    411
    -  return charMaps_[charMapSelector_->currentIndex() - 1]
    
    412
    -           .stringifyIndexShort(index);
    
    413
    -}
    
    414
    -
    
    415
    -
    
    416
    -void
    
    417
    -ContinousAllGlyphsTab::charMapChanged()
    
    418
    -{
    
    419
    -  int newIndex = charMapSelector_->currentIndex();
    
    420
    -  if (newIndex != lastCharMapIndex_)
    
    421
    -  {
    
    422
    -    if (newIndex <= 0
    
    423
    -        || charMaps_.size() <= static_cast<unsigned>(newIndex - 1))
    
    424
    -      setGlyphBeginindex(0);
    
    425
    -    else if (charMaps_[newIndex - 1].maxIndex <= 20)
    
    426
    -      setGlyphBeginindex(charMaps_[newIndex - 1].maxIndex - 1);
    
    427
    -    else
    
    428
    -      setGlyphBeginindex(0x20);
    
    429
    -  }
    
    430
    -  updateLimitIndex();
    
    431
    -
    
    432
    -  emit changed();
    
    372
    +          this, &ContinuousTab::repaintGlyph);
    
    373
    +  connect(rotationSpinBox_, 
    
    374
    +          QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    375
    +          this, &ContinuousTab::repaintGlyph);
    
    433 376
     
    
    434
    -  lastCharMapIndex_ = newIndex;
    
    377
    +  connect(waterfallCheckBox_, &QCheckBox::clicked,
    
    378
    +          this, &ContinuousTab::repaintGlyph);
    
    379
    +  connect(verticalCheckBox_, &QCheckBox::clicked,
    
    380
    +          this, &ContinuousTab::repaintGlyph);
    
    381
    +  connect(sourceTextEdit_, &QPlainTextEdit::textChanged,
    
    382
    +          this, &ContinuousTab::sourceTextChanged);
    
    435 383
     }
    
    436 384
     
    
    437 385
     
    
    438 386
     void
    
    439
    -ContinousAllGlyphsTab::setDefaults()
    
    387
    +ContinuousTab::setDefaults()
    
    440 388
     {
    
    441 389
       xEmboldeningSpinBox_->setValue(0.04);
    
    442 390
       yEmboldeningSpinBox_->setValue(0.04);
    
    443 391
       slantSpinBox_->setValue(0.22);
    
    444 392
       strokeRadiusSpinBox_->setValue(0.02);
    
    393
    +  rotationSpinBox_->setValue(0);
    
    394
    +}
    
    395
    +
    
    396
    +
    
    397
    +QString
    
    398
    +ContinuousTab::formatIndex(int index)
    
    399
    +{
    
    400
    +  if (charMapSelector_->currentIndex() <= 0) // glyph order
    
    401
    +    return QString::number(index);
    
    402
    +  return charMaps_[charMapSelector_->currentIndex() - 1].stringifyIndexShort(
    
    403
    +      index);
    
    445 404
     }
    
    446 405
     
    
    447 406
     
    

  • src/ftinspect/panels/continuous.hpp
    ... ... @@ -18,8 +18,8 @@
    18 18
     #include <QComboBox>
    
    19 19
     #include <QGridLayout>
    
    20 20
     #include <QBoxLayout>
    
    21
    -
    
    22
    -class ContinousAllGlyphsTab;
    
    21
    +#include <QPlainTextEdit>
    
    22
    +#include <QCheckBox>
    
    23 23
     
    
    24 24
     class ContinuousTab
    
    25 25
     : public QWidget, public AbstractTab
    
    ... ... @@ -31,106 +31,72 @@ public:
    31 31
     
    
    32 32
       void repaintGlyph() override;
    
    33 33
       void reloadFont() override;
    
    34
    -
    
    35
    -  // Info about current font (glyph count, charmaps...) is flowed to subtab
    
    36
    -  // via `updateCurrentSubTab`.
    
    37
    -  // Settings and parameters (e.g. mode) are flowed from subtab to `this` via
    
    38
    -  // `updateFromCurrentSubTab`.
    
    39
    -  // SubTabs can notify `this` via signals, see `createConnections`
    
    40
    -  void updateCurrentSubTab();
    
    41
    -  void updateFromCurrentSubTab();
    
    42
    -
    
    43
    -private slots:
    
    44
    -  void changeTab();
    
    45
    -  void wheelNavigate(int steps);
    
    46
    -  void wheelResize(int steps);
    
    47
    -
    
    48
    -private:
    
    49
    -  Engine* engine_;
    
    50
    -
    
    51
    -  int currentGlyphCount_;
    
    52
    -  GlyphContinuous* canvas_;
    
    53
    -  
    
    54
    -  FontSizeSelector* sizeSelector_;
    
    55
    -
    
    56
    -  QTabWidget* tabWidget_;
    
    57
    -  ContinousAllGlyphsTab* allGlyphsTab_;
    
    58
    -
    
    59
    -  enum Tabs
    
    60
    -  {
    
    61
    -    AllGlyphs = 0
    
    62
    -  };
    
    63
    -
    
    64
    -  QVBoxLayout* mainLayout_;
    
    65
    -  
    
    66
    -  void createLayout();
    
    67
    -  void createConnections();
    
    68
    -};
    
    69
    -
    
    70
    -
    
    71
    -class ContinousAllGlyphsTab
    
    72
    -: public QWidget
    
    73
    -{
    
    74
    -  Q_OBJECT
    
    75
    -public:
    
    76
    -  explicit ContinousAllGlyphsTab(QWidget* parent);
    
    77
    -  ~ContinousAllGlyphsTab() override = default;
    
    78
    -
    
    79
    -  int glyphBeginindex();
    
    80
    -  int glyphLimitIndex();
    
    81
    -  GlyphContinuous::SubModeAllGlyphs subMode();
    
    82
    -  double xEmboldening();
    
    83
    -  double yEmboldening();
    
    84
    -  double slanting();
    
    85
    -  double strokeRadius();
    
    34
    +  void syncSettings();
    
    86 35
     
    
    87 36
       // -1: Glyph order, otherwise the char map index in the original list
    
    88 37
       int charMapIndex();
    
    89
    -  void setGlyphBeginindex(int index);
    
    90 38
     
    
    91 39
       // This doesn't trigger immediate repaint
    
    92 40
       void setGlyphCount(int count);
    
    93 41
       void setDisplayingCount(int count);
    
    42
    +  void setGlyphBeginindex(int index);
    
    94 43
     
    
    95 44
       void setCharMaps(std::vector<CharMapInfo>& charMaps);
    
    96 45
       // This doesn't trigger either.
    
    97 46
       void updateLimitIndex();
    
    47
    +  void checkMode();
    
    48
    +  void checkSource();
    
    49
    +  void charMapChanged();
    
    50
    +  void sourceTextChanged();
    
    98 51
     
    
    99
    -  void checkSubMode();
    
    100
    -
    
    101
    -signals:
    
    102
    -  void changed();
    
    52
    +private slots:
    
    53
    +  void wheelNavigate(int steps);
    
    54
    +  void wheelResize(int steps);
    
    103 55
     
    
    104 56
     private:
    
    105
    -  int lastCharMapIndex_ = 0;
    
    57
    +  Engine* engine_;
    
    58
    +
    
    106 59
       int currentGlyphCount_;
    
    60
    +  int lastCharMapIndex_ = 0;
    
    107 61
       int glyphLimitIndex_ = 0;
    
    108 62
     
    
    109
    -  GlyphIndexSelector* indexSelector_;
    
    63
    +  GlyphContinuous* canvas_;
    
    64
    +  FontSizeSelector* sizeSelector_;
    
    65
    +
    
    110 66
       QComboBox* modeSelector_;
    
    67
    +  QComboBox* sourceSelector_;
    
    111 68
       QComboBox* charMapSelector_;
    
    112 69
     
    
    113 70
       QLabel* modeLabel_;
    
    71
    +  QLabel* sourceLabel_;
    
    114 72
       QLabel* charMapLabel_;
    
    115 73
       QLabel* xEmboldeningLabel_;
    
    116 74
       QLabel* yEmboldeningLabel_;
    
    117 75
       QLabel* slantLabel_;
    
    118 76
       QLabel* strokeRadiusLabel_;
    
    77
    +  QLabel* rotationLabel_;
    
    119 78
     
    
    120 79
       QDoubleSpinBox* xEmboldeningSpinBox_;
    
    121 80
       QDoubleSpinBox* yEmboldeningSpinBox_;
    
    122 81
       QDoubleSpinBox* slantSpinBox_;
    
    123 82
       QDoubleSpinBox* strokeRadiusSpinBox_;
    
    83
    +  QDoubleSpinBox* rotationSpinBox_;
    
    84
    +
    
    85
    +  QCheckBox* verticalCheckBox_;
    
    86
    +  QCheckBox* waterfallCheckBox_;
    
    124 87
     
    
    125
    -  QGridLayout* layout_;
    
    88
    +  GlyphIndexSelector* indexSelector_;
    
    89
    +  QPlainTextEdit* sourceTextEdit_;
    
    126 90
     
    
    127 91
       std::vector<CharMapInfo> charMaps_;
    
    128 92
     
    
    93
    +  QGridLayout* bottomLayout_;
    
    94
    +  QVBoxLayout* mainLayout_;
    
    95
    +  
    
    129 96
       void createLayout();
    
    130 97
       void createConnections();
    
    131 98
     
    
    132 99
       QString formatIndex(int index);
    
    133
    -  void charMapChanged();
    
    134 100
     
    
    135 101
       void setDefaults();
    
    136 102
     };
    

  • src/ftinspect/panels/singular.cpp
    ... ... @@ -5,6 +5,7 @@
    5 5
     #include "singular.hpp"
    
    6 6
     
    
    7 7
     #include <QSizePolicy>
    
    8
    +#include <QToolTip>
    
    8 9
     #include <QWheelEvent>
    
    9 10
     
    
    10 11
     
    
    ... ... @@ -197,6 +198,25 @@ SingularTab::wheelResize(QWheelEvent* event)
    197 198
     }
    
    198 199
     
    
    199 200
     
    
    201
    +void
    
    202
    +SingularTab::setGridVisible()
    
    203
    +{
    
    204
    +  gridItem_->setVisible(showGridCheckBox_->isChecked());
    
    205
    +}
    
    206
    +
    
    207
    +
    
    208
    +void
    
    209
    +SingularTab::showToolTip()
    
    210
    +{
    
    211
    +  QToolTip::showText(helpButton_->pos(),
    
    212
    +                     tr("Scroll: Grid Up/Down\n"
    
    213
    +                        "Alt + Scroll: Grid Left/Right\n"
    
    214
    +                        "Ctrl + Scroll: Adjust Zoom (Relative to cursor)\n"
    
    215
    +                        "Shift + Scroll: Adjust Font Size"),
    
    216
    +                     helpButton_);
    
    217
    +}
    
    218
    +
    
    219
    +
    
    200 220
     void
    
    201 221
     SingularTab::createLayout()
    
    202 222
     {
    
    ... ... @@ -215,6 +235,7 @@ SingularTab::createLayout()
    215 235
       glyphView_->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    
    216 236
       glyphView_->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    
    217 237
       glyphView_->setScene(glyphScene_);
    
    238
    +  glyphView_->setBackgroundBrush(Qt::white);
    
    218 239
     
    
    219 240
       gridItem_ = new Grid(glyphView_, graphicsDefault_->gridPen, 
    
    220 241
                            graphicsDefault_->axisPen);
    
    ... ... @@ -222,26 +243,21 @@ SingularTab::createLayout()
    222 243
     
    
    223 244
       // Don't use QGraphicsTextItem: We want this hint to be anchored at the
    
    224 245
       // top-left corner.
    
    225
    -  mouseUsageHint_ = new QLabel(tr(
    
    226
    -                      "Scroll: Grid Up/Down\n"
    
    227
    -                      "Alt + Scroll: Grid Left/Right\n"
    
    228
    -                      "Ctrl + Scroll: Adjust Zoom (Relative to cursor)\n"
    
    229
    -                      "Shift + Scroll: Adjust Font Size"),
    
    230
    -                      glyphView_);
    
    231
    -  auto hintFont = font();
    
    232
    -  hintFont.setPixelSize(24);
    
    233
    -  mouseUsageHint_->setFont(hintFont);
    
    234
    -  mouseUsageHint_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    246
    +  auto overlayFont = font();
    
    247
    +  overlayFont.setPixelSize(24);
    
    235 248
     
    
    236 249
       glyphIndexLabel_ = new QLabel(glyphView_);
    
    237 250
       glyphNameLabel_ = new QLabel(glyphView_);
    
    238
    -  glyphIndexLabel_->setFont(hintFont);
    
    239
    -  glyphNameLabel_->setFont(hintFont);
    
    251
    +  glyphIndexLabel_->setFont(overlayFont);
    
    252
    +  glyphNameLabel_->setFont(overlayFont);
    
    240 253
       glyphIndexLabel_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    
    241 254
       glyphNameLabel_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    
    242 255
       glyphIndexLabel_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    243 256
       glyphNameLabel_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    244 257
     
    
    258
    +  glyphIndexLabel_->setStyleSheet("QLabel { color : black; }");
    
    259
    +  glyphNameLabel_->setStyleSheet("QLabel { color : black; }");
    
    260
    +
    
    245 261
       indexSelector_ = new GlyphIndexSelector(this);
    
    246 262
       indexSelector_->setSingleMode(true);
    
    247 263
     
    
    ... ... @@ -256,11 +272,18 @@ SingularTab::createLayout()
    256 272
       zoomLabel_->setBuddy(zoomSpinBox_);
    
    257 273
     
    
    258 274
       centerGridButton_ = new QPushButton("Go Back to Grid Center", this);
    
    275
    +  helpButton_ = new QPushButton("?", this);
    
    276
    +  helpButton_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    
    259 277
     
    
    260 278
       showBitmapCheckBox_ = new QCheckBox(tr("Show Bitmap"), this);
    
    261 279
       showPointsCheckBox_ = new QCheckBox(tr("Show Points"), this);
    
    262 280
       showPointNumbersCheckBox_ = new QCheckBox(tr("Show Point Numbers"), this);
    
    263 281
       showOutlinesCheckBox_ = new QCheckBox(tr("Show Outlines"), this);
    
    282
    +  showGridCheckBox_ = new QCheckBox(tr("Show Grid"), this);
    
    283
    +
    
    284
    +  indexHelpLayout_ = new QHBoxLayout;
    
    285
    +  indexHelpLayout_->addWidget(indexSelector_, 1);
    
    286
    +  indexHelpLayout_->addWidget(helpButton_);
    
    264 287
     
    
    265 288
       sizeLayout_ = new QHBoxLayout;
    
    266 289
       sizeLayout_->addStretch(2);
    
    ... ... @@ -278,20 +301,19 @@ SingularTab::createLayout()
    278 301
       checkBoxesLayout_->addWidget(showPointsCheckBox_);
    
    279 302
       checkBoxesLayout_->addWidget(showPointNumbersCheckBox_);
    
    280 303
       checkBoxesLayout_->addWidget(showOutlinesCheckBox_);
    
    304
    +  checkBoxesLayout_->addWidget(showGridCheckBox_);
    
    281 305
     
    
    282 306
       glyphOverlayIndexLayout_ = new QHBoxLayout;
    
    283 307
       glyphOverlayIndexLayout_->addWidget(glyphIndexLabel_);
    
    284 308
       glyphOverlayIndexLayout_->addWidget(glyphNameLabel_);
    
    285 309
       glyphOverlayLayout_ = new QGridLayout;
    
    286
    -  glyphOverlayLayout_->addWidget(mouseUsageHint_, 0, 0,
    
    287
    -                                 Qt::AlignTop | Qt::AlignLeft);
    
    288 310
       glyphOverlayLayout_->addLayout(glyphOverlayIndexLayout_, 0, 1,
    
    289 311
                                      Qt::AlignTop | Qt::AlignRight);
    
    290 312
       glyphView_->setLayout(glyphOverlayLayout_);
    
    291 313
     
    
    292 314
       mainLayout_ = new QVBoxLayout;
    
    293 315
       mainLayout_->addWidget(glyphView_);
    
    294
    -  mainLayout_->addWidget(indexSelector_);
    
    316
    +  mainLayout_->addLayout(indexHelpLayout_);
    
    295 317
       mainLayout_->addSpacing(10); // XXX px
    
    296 318
       mainLayout_->addLayout(sizeLayout_);
    
    297 319
       mainLayout_->addLayout(checkBoxesLayout_);
    
    ... ... @@ -322,6 +344,8 @@ SingularTab::createConnections()
    322 344
     
    
    323 345
       connect(centerGridButton_, &QPushButton::clicked,
    
    324 346
               this, &SingularTab::backToCenter);
    
    347
    +  connect(helpButton_, &QPushButton::clicked,
    
    348
    +          this, &SingularTab::showToolTip);
    
    325 349
     
    
    326 350
       connect(showBitmapCheckBox_, &QCheckBox::clicked,
    
    327 351
               this, &SingularTab::drawGlyph);
    
    ... ... @@ -331,6 +355,8 @@ SingularTab::createConnections()
    331 355
               this, &SingularTab::drawGlyph);
    
    332 356
       connect(showOutlinesCheckBox_, &QCheckBox::clicked,
    
    333 357
               this, &SingularTab::drawGlyph);
    
    358
    +  connect(showGridCheckBox_, &QCheckBox::clicked,
    
    359
    +          this, &SingularTab::setGridVisible);
    
    334 360
     }
    
    335 361
     
    
    336 362
     
    
    ... ... @@ -365,6 +391,7 @@ SingularTab::setDefaults()
    365 391
       zoomSpinBox_->setValue(20);
    
    366 392
       showBitmapCheckBox_->setChecked(true);
    
    367 393
       showOutlinesCheckBox_->setChecked(true);
    
    394
    +  showGridCheckBox_->setChecked(true);
    
    368 395
       
    
    369 396
       indexSelector_->setCurrentIndex(indexSelector_->currentIndex(), true);
    
    370 397
       zoom();
    

  • src/ftinspect/panels/singular.hpp
    ... ... @@ -52,6 +52,8 @@ private slots:
    52 52
       void backToCenter();
    
    53 53
       void wheelZoom(QWheelEvent* event);
    
    54 54
       void wheelResize(QWheelEvent* event);
    
    55
    +  void setGridVisible();
    
    56
    +  void showToolTip();
    
    55 57
     
    
    56 58
     private:
    
    57 59
       int currentGlyphIndex_;
    
    ... ... @@ -67,13 +69,13 @@ private:
    67 69
       GlyphPointNumbers* currentGlyphPointNumbersItem_;
    
    68 70
       GlyphBitmap* currentGlyphBitmapItem_;
    
    69 71
       Grid* gridItem_ = NULL;
    
    70
    -  QLabel* mouseUsageHint_;
    
    71 72
     
    
    72 73
       GlyphIndexSelector* indexSelector_;
    
    73 74
       FontSizeSelector* sizeSelector_;
    
    74 75
       QLabel* zoomLabel_;
    
    75 76
       ZoomSpinBox* zoomSpinBox_;
    
    76 77
       QPushButton* centerGridButton_;
    
    78
    +  QPushButton* helpButton_;
    
    77 79
     
    
    78 80
       QLabel* glyphIndexLabel_;
    
    79 81
       QLabel* glyphNameLabel_;
    
    ... ... @@ -82,9 +84,11 @@ private:
    82 84
       QCheckBox* showOutlinesCheckBox_;
    
    83 85
       QCheckBox* showPointNumbersCheckBox_;
    
    84 86
       QCheckBox* showPointsCheckBox_;
    
    87
    +  QCheckBox* showGridCheckBox_;
    
    85 88
     
    
    86 89
       QVBoxLayout* mainLayout_;
    
    87 90
       QHBoxLayout* checkBoxesLayout_;
    
    91
    +  QHBoxLayout* indexHelpLayout_;
    
    88 92
       QHBoxLayout* sizeLayout_;
    
    89 93
       QGridLayout* glyphOverlayLayout_;
    
    90 94
       QHBoxLayout* glyphOverlayIndexLayout_;
    

  • src/ftinspect/rendering/glyphbitmap.cpp
    ... ... @@ -18,7 +18,7 @@ GlyphBitmap::GlyphBitmap(FT_Glyph glyph,
    18 18
                              Engine* engine)
    
    19 19
     {
    
    20 20
       QRect bRect;
    
    21
    -  image_ = engine->convertBitmapToQImage(glyph, &bRect);
    
    21
    +  image_ = engine->convertGlyphToQImage(glyph, &bRect);
    
    22 22
       boundingRect_ = bRect; // QRectF to QRect
    
    23 23
     }
    
    24 24
     
    

  • src/ftinspect/rendering/glyphcontinuous.cpp
    ... ... @@ -11,13 +11,14 @@
    11 11
     #include <QPainter>
    
    12 12
     #include <QWheelEvent>
    
    13 13
     
    
    14
    +#include <freetype/ftbitmap.h>
    
    15
    +
    
    14 16
     
    
    15 17
     GlyphContinuous::GlyphContinuous(QWidget* parent, Engine* engine)
    
    16 18
     : QWidget(parent), engine_(engine)
    
    17 19
     {
    
    18 20
       setAcceptDrops(false);
    
    19 21
       setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
    20
    -  graphicsDefault_ = GraphicsDefault::deafultInstance();
    
    21 22
     
    
    22 23
       FT_Stroker_New(engine_->ftLibrary(), &stroker_);
    
    23 24
     }
    
    ... ... @@ -41,21 +42,19 @@ GlyphContinuous::paintEvent(QPaintEvent* event)
    41 42
       {
    
    42 43
         prePaint();
    
    43 44
     
    
    44
    -    switch (mode_)
    
    45
    +    switch (source_)
    
    45 46
         {
    
    46
    -    case AllGlyphs:
    
    47
    -      switch (modeAG_)
    
    47
    +    case SRC_AllGlyphs:
    
    48
    +      switch (mode_)
    
    48 49
           {
    
    49
    -      case AG_AllGlyphs:
    
    50
    -      case AG_Fancy:
    
    51
    -      case AG_Stroked:
    
    50
    +      case M_Normal:
    
    51
    +      case M_Fancy:
    
    52
    +      case M_Stroked:
    
    52 53
             paintAG(&painter);
    
    53 54
             break;
    
    54
    -      case AG_Waterfall:
    
    55
    -        break;
    
    56 55
           }
    
    57 56
           break;
    
    58
    -    case TextString:
    
    57
    +    case SRC_TextString:
    
    59 58
           break;
    
    60 59
         }
    
    61 60
         emit displayingCountUpdated(displayingCount_);
    
    ... ... @@ -79,7 +78,7 @@ GlyphContinuous::wheelEvent(QWheelEvent* event)
    79 78
     void
    
    80 79
     GlyphContinuous::paintAG(QPainter* painter)
    
    81 80
     {
    
    82
    -  if (modeAG_ == AG_Stroked)
    
    81
    +  if (mode_ == M_Stroked)
    
    83 82
       {
    
    84 83
         auto radius = static_cast<FT_Fixed>(metrics_.y_ppem * 64 * strokeRadius_);
    
    85 84
         FT_Stroker_Set(stroker_, radius,
    
    ... ... @@ -98,13 +97,13 @@ GlyphContinuous::paintAG(QPainter* painter)
    98 97
           break;
    
    99 98
     
    
    100 99
         // All Glyphs need no tranformation, and Waterfall isn't handled here.
    
    101
    -    switch (modeAG_)
    
    100
    +    switch (mode_)
    
    102 101
         {
    
    103
    -    case AG_Fancy:
    
    104
    -      transformGlyphAGFancy();
    
    102
    +    case M_Fancy:
    
    103
    +      transformGlyphFancy();
    
    105 104
           break;
    
    106
    -    case AG_Stroked:
    
    107
    -      transformGlyphAGStroked();
    
    105
    +    case M_Stroked:
    
    106
    +      transformGlyphStroked();
    
    108 107
           break;
    
    109 108
         default:;
    
    110 109
         }
    
    ... ... @@ -120,7 +119,7 @@ GlyphContinuous::paintAG(QPainter* painter)
    120 119
     
    
    121 120
     
    
    122 121
     void
    
    123
    -GlyphContinuous::transformGlyphAGFancy()
    
    122
    +GlyphContinuous::transformGlyphFancy()
    
    124 123
     {
    
    125 124
       // adopted from ftview.c:289
    
    126 125
       /***************************************************************/
    
    ... ... @@ -148,41 +147,52 @@ GlyphContinuous::transformGlyphAGFancy()
    148 147
       xstr = (FT_Pos)(metrics_.y_ppem * 64 * boldX_);
    
    149 148
       ystr = (FT_Pos)(metrics_.y_ppem * 64 * boldY_);
    
    150 149
     
    
    151
    -  if (!isGlyphCloned_)
    
    152
    -    cloneGlyph();
    
    153
    -
    
    154
    -  if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
    
    155
    -    return; // TODO suuport non-outline: code below all depend on `outline_`!
    
    156
    -
    
    157
    -  FT_Outline_Transform(&outline_, &shear);
    
    158
    -  FT_Outline_EmboldenXY(&outline_, xstr, ystr);
    
    150
    +  if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
    
    151
    +  {
    
    152
    +    if (!isGlyphCloned_)
    
    153
    +      cloneGlyph();
    
    154
    +    FT_Outline_Transform(&outline_, &shear);
    
    155
    +    if (FT_Outline_EmboldenXY(&outline_, xstr, ystr))
    
    156
    +    {
    
    157
    +      // XXX error handling?
    
    158
    +      return;
    
    159
    +    }
    
    159 160
     
    
    160
    -  if (glyph_->advance.x)
    
    161
    -    glyph_->advance.x += xstr;
    
    161
    +    if (glyph_->advance.x)
    
    162
    +      glyph_->advance.x += xstr;
    
    162 163
     
    
    163
    -  if (glyph_->advance.y)
    
    164
    -    glyph_->advance.y += ystr;
    
    165
    -  
    
    166
    -  //glyph_->metrics.width += xstr;
    
    167
    -  //glyph_->metrics.height += ystr;
    
    168
    -  //glyph_->metrics.horiAdvance += xstr;
    
    169
    -  //glyph_->metrics.vertAdvance += ystr;
    
    164
    +    if (glyph_->advance.y)
    
    165
    +      glyph_->advance.y += ystr;
    
    166
    +  }
    
    167
    +  else if (glyph_->format == FT_GLYPH_FORMAT_BITMAP)
    
    168
    +  {
    
    169
    +    if (!isBitmapCloned_)
    
    170
    +      cloneBitmap();
    
    171
    +    xstr &= ~63;
    
    172
    +    ystr &= ~63;
    
    173
    +
    
    174
    +    // No shearing support for bitmap
    
    175
    +    FT_Bitmap_Embolden(engine_->ftLibrary(), &bitmap_, 
    
    176
    +                       xstr, ystr);
    
    177
    +  }
    
    178
    +  else
    
    179
    +    return; // XXX no support for SVG
    
    170 180
     }
    
    171 181
     
    
    172 182
     
    
    173 183
     void
    
    174
    -GlyphContinuous::transformGlyphAGStroked()
    
    184
    +GlyphContinuous::transformGlyphStroked()
    
    175 185
     {
    
    176
    -  //if (!isGlyphCloned_)
    
    177
    -    //cloneGlyph();
    
    178
    -  // Well, now here only outline glyph is supported.
    
    186
    +  // Well, here only outline glyph is supported.
    
    179 187
       if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
    
    180 188
         return;
    
    189
    +  auto oldGlyph = glyph_;
    
    181 190
       auto error = FT_Glyph_Stroke(&glyph_, stroker_, 0);
    
    182 191
       if (!error)
    
    183 192
       {
    
    193
    +    if (isGlyphCloned_)
    
    194
    +      FT_Done_Glyph(oldGlyph);
    
    184 195
         isGlyphCloned_ = true;
    
    185
    -    isOutlineCloned_ = false;
    
    186 196
         outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
    
    187 197
       }
    
    188 198
     }
    
    ... ... @@ -230,61 +240,19 @@ GlyphContinuous::paintChar(QPainter* painter)
    230 240
       // XXX: this is different from what's being done in
    
    231 241
       // `ftcommon.c`:FTDemo_Draw_Slot: is this correct??
    
    232 242
     
    
    233
    -  // First translate the outline
    
    234
    -
    
    235
    -  if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
    
    236
    -    return true; // XXX only outline is supported - need to impl others later
    
    237
    -
    
    238
    -  FT_BBox cbox;
    
    239
    -  // Don't forget to free this when returning
    
    240
    -  if (!isOutlineCloned_ && !isGlyphCloned_)
    
    241
    -    cloneOutline();
    
    243
    +  QImage* image;
    
    242 244
       
    
    243
    -  transformOutlineToOrigin(&outline_, &cbox);
    
    244
    -  
    
    245
    -  auto outlineWidth = (cbox.xMax - cbox.xMin) / 64;
    
    246
    -  auto outlineHeight = (cbox.yMax - cbox.yMin) / 64;
    
    247
    -
    
    248
    -  // Then convert to bitmap
    
    249
    -  FT_Bitmap bitmap;
    
    250
    -  QImage::Format format = QImage::Format_Indexed8;
    
    251
    -  auto aaEnabled = engine_->antiAliasingEnabled();
    
    252
    -
    
    253
    -  // TODO cover LCD and color
    
    254
    -  if (!aaEnabled)
    
    255
    -    format = QImage::Format_Mono;
    
    256
    -
    
    257
    -  // TODO optimization: reuse QImage?
    
    258
    -  QImage image(QSize(outlineWidth, outlineHeight), format);
    
    259
    -
    
    260
    -  if (!aaEnabled)
    
    261
    -    image.setColorTable(graphicsDefault_->monoColorTable);
    
    245
    +  if (bitmap_.buffer) // Always prefer `bitmap_` since it can be manipulated
    
    246
    +    image = engine_->convertBitmapToQImage(&bitmap_);
    
    262 247
       else
    
    263
    -    image.setColorTable(graphicsDefault_->grayColorTable);
    
    264
    -
    
    265
    -  image.fill(0);
    
    266
    -
    
    267
    -  bitmap.rows = static_cast<unsigned int>(outlineHeight);
    
    268
    -  bitmap.width = static_cast<unsigned int>(outlineWidth);
    
    269
    -  bitmap.buffer = image.bits();
    
    270
    -  bitmap.pitch = image.bytesPerLine();
    
    271
    -  bitmap.pixel_mode = aaEnabled ? FT_PIXEL_MODE_GRAY : FT_PIXEL_MODE_MONO;
    
    272
    -
    
    273
    -  FT_Error error = FT_Outline_Get_Bitmap(engine_->ftLibrary(),
    
    274
    -                                         &outline_,
    
    275
    -                                         &bitmap);
    
    276
    -  if (error)
    
    277
    -  {
    
    278
    -    // XXX error handling
    
    279
    -    return true;
    
    280
    -  }
    
    248
    +    image = engine_->convertGlyphToQImage(glyph_, NULL);
    
    249
    +  auto offset = engine_->computeGlyphOffset(glyph_);
    
    281 250
     
    
    282
    -  painter->drawImage(
    
    283
    -      QPoint(x_ + cbox.xMin / 64, y_ + (-cbox.yMax / 64)),
    
    284
    -      image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
    
    251
    +  painter->drawImage(offset + QPoint(x_, y_),
    
    252
    +                     *image);
    
    253
    +  delete image;
    
    285 254
     
    
    286 255
       x_ += width;
    
    287
    -  
    
    288 256
       return true;
    
    289 257
     }
    
    290 258
     
    
    ... ... @@ -292,15 +260,13 @@ GlyphContinuous::paintChar(QPainter* painter)
    292 260
     bool
    
    293 261
     GlyphContinuous::loadGlyph(int index)
    
    294 262
     {
    
    263
    +  if (isGlyphCloned_)
    
    264
    +    FT_Done_Glyph(glyph_);
    
    295 265
       glyph_ = engine_->loadGlyphWithoutUpdate(index);
    
    296 266
       isGlyphCloned_ = false;
    
    297 267
       if (!glyph_)
    
    298 268
         return false;
    
    299
    -  if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
    
    300
    -  {
    
    301
    -    isOutlineCloned_ = false;
    
    302
    -    outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
    
    303
    -  }
    
    269
    +  refreshOutlineOrBitmapFromGlyph();
    
    304 270
       return true;
    
    305 271
     }
    
    306 272
     
    
    ... ... @@ -308,16 +274,57 @@ GlyphContinuous::loadGlyph(int index)
    308 274
     void
    
    309 275
     GlyphContinuous::cloneGlyph()
    
    310 276
     {
    
    277
    +  if (isGlyphCloned_)
    
    278
    +    return;
    
    311 279
       glyph_ = ::cloneGlyph(glyph_);
    
    280
    +  refreshOutlineOrBitmapFromGlyph();
    
    312 281
       isGlyphCloned_ = true;
    
    313 282
     }
    
    314 283
     
    
    315 284
     
    
    316 285
     void
    
    317
    -GlyphContinuous::cloneOutline()
    
    286
    +GlyphContinuous::cloneBitmap()
    
    287
    +{
    
    288
    +  if (isBitmapCloned_)
    
    289
    +    return;
    
    290
    +  bitmap_ = ::cloneBitmap(engine_->ftLibrary(), &bitmap_);
    
    291
    +  isBitmapCloned_ = true;
    
    292
    +}
    
    293
    +
    
    294
    +
    
    295
    +void
    
    296
    +GlyphContinuous::refreshOutlineOrBitmapFromGlyph()
    
    318 297
     {
    
    319
    -  outline_ = ::cloneOutline(engine_->ftLibrary(), &outline_);
    
    320
    -  isOutlineCloned_ = true;
    
    298
    +  if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
    
    299
    +  {
    
    300
    +    outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
    
    301
    +
    
    302
    +    // Make `bitmap_` invalid
    
    303
    +    if (isBitmapCloned_)
    
    304
    +      FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
    
    305
    +    isBitmapCloned_ = false;
    
    306
    +    bitmap_.buffer = NULL;
    
    307
    +  }
    
    308
    +  else if (glyph_->format == FT_GLYPH_FORMAT_BITMAP)
    
    309
    +  {
    
    310
    +    // Initialize `bitmap_`
    
    311
    +    if (isBitmapCloned_)
    
    312
    +      FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
    
    313
    +    isBitmapCloned_ = false;
    
    314
    +    bitmap_ = reinterpret_cast<FT_BitmapGlyph>(glyph_)->bitmap;
    
    315
    +
    
    316
    +    outline_.points = NULL;
    
    317
    +  }
    
    318
    +  else
    
    319
    +  {
    
    320
    +    // Both invalid.
    
    321
    +    outline_.points = NULL;
    
    322
    +
    
    323
    +    if (isBitmapCloned_)
    
    324
    +      FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
    
    325
    +    isBitmapCloned_ = false;
    
    326
    +    bitmap_.buffer = NULL;
    
    327
    +  }
    
    321 328
     }
    
    322 329
     
    
    323 330
     
    
    ... ... @@ -326,13 +333,17 @@ GlyphContinuous::cleanCloned()
    326 333
     {
    
    327 334
       if (isGlyphCloned_)
    
    328 335
       {
    
    336
    +    if (glyph_->format == FT_GLYPH_FORMAT_BITMAP && !isBitmapCloned_)
    
    337
    +      bitmap_.buffer = NULL;
    
    338
    +
    
    329 339
         FT_Done_Glyph(glyph_);
    
    330 340
         isGlyphCloned_ = false;
    
    331 341
       }
    
    332
    -  if (isOutlineCloned_)
    
    342
    +  if (isBitmapCloned_)
    
    333 343
       {
    
    334
    -    FT_Outline_Done(engine_->ftLibrary(), &outline_);
    
    335
    -    isOutlineCloned_ = false;
    
    344
    +    FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
    
    345
    +    bitmap_.buffer = NULL;
    
    346
    +    isBitmapCloned_ = false;
    
    336 347
       }
    
    337 348
     }
    
    338 349
     
    

  • src/ftinspect/rendering/glyphcontinuous.hpp
    ... ... @@ -5,12 +5,17 @@
    5 5
     #pragma once
    
    6 6
     
    
    7 7
     #include "graphicsdefault.hpp"
    
    8
    +
    
    9
    +#include <utility>
    
    10
    +
    
    8 11
     #include <QWidget>
    
    12
    +
    
    9 13
     #include <freetype/freetype.h>
    
    10 14
     #include <freetype/ftglyph.h>
    
    11 15
     #include <freetype/ftoutln.h>
    
    12 16
     #include <freetype/ftstroke.h>
    
    13 17
     
    
    18
    +
    
    14 19
     class Engine;
    
    15 20
     class GlyphContinuous
    
    16 21
     : public QWidget
    
    ... ... @@ -20,18 +25,18 @@ public:
    20 25
       GlyphContinuous(QWidget* parent, Engine* engine);
    
    21 26
       ~GlyphContinuous() override;
    
    22 27
     
    
    23
    -  enum Mode : int
    
    28
    +  enum Source : int
    
    24 29
       {
    
    25
    -    AllGlyphs,
    
    26
    -    TextString
    
    30
    +    SRC_AllGlyphs,
    
    31
    +    SRC_TextString,
    
    32
    +    SRC_TextStringRepeated
    
    27 33
       };
    
    28 34
     
    
    29
    -  enum SubModeAllGlyphs : int
    
    35
    +  enum Mode : int
    
    30 36
       {
    
    31
    -    AG_AllGlyphs,
    
    32
    -    AG_Fancy,
    
    33
    -    AG_Stroked,
    
    34
    -    AG_Waterfall
    
    37
    +    M_Normal,
    
    38
    +    M_Fancy,
    
    39
    +    M_Stroked
    
    35 40
       };
    
    36 41
     
    
    37 42
       int displayingCount() { return displayingCount_; }
    
    ... ... @@ -40,8 +45,8 @@ public:
    40 45
       void setBeginIndex(int index) { beginIndex_ = index; }
    
    41 46
       void setLimitIndex(int index) { limitIndex_ = index; }
    
    42 47
       void setCharMapIndex(int index) { charMapIndex_ = index; }
    
    48
    +  void setSource(Source mode) { source_ = mode; }
    
    43 49
       void setMode(Mode mode) { mode_ = mode; }
    
    44
    -  void setSubModeAllGlyphs(SubModeAllGlyphs modeAg) { modeAG_ = modeAg; }
    
    45 50
       void setFancyParams(double boldX, double boldY, double slant)
    
    46 51
       {
    
    47 52
         boldX_ = boldX;
    
    ... ... @@ -49,6 +54,10 @@ public:
    49 54
         slant_ = slant;
    
    50 55
       }
    
    51 56
       void setStrokeRadius(double radius) { strokeRadius_ = radius; }
    
    57
    +  void setRotation(double rotation) { rotation_ = rotation; }
    
    58
    +  void setVertical(bool vertical) { vertical_ = vertical; }
    
    59
    +  void setWaterfall(bool waterfall) { waterfall_ = waterfall; }
    
    60
    +  void setSourceText(QString text) { text_ = std::move(text); }
    
    52 61
     
    
    53 62
     signals:
    
    54 63
       void wheelNavigate(int steps);
    
    ... ... @@ -61,37 +70,52 @@ protected:
    61 70
     
    
    62 71
     private:
    
    63 72
       Engine* engine_;
    
    64
    -  GraphicsDefault* graphicsDefault_;
    
    65 73
     
    
    66
    -  Mode mode_ = AllGlyphs;
    
    67
    -  SubModeAllGlyphs modeAG_ = AG_AllGlyphs;
    
    74
    +  Source source_ = SRC_AllGlyphs;
    
    75
    +  Mode mode_ = M_Normal;
    
    68 76
       int beginIndex_;
    
    69 77
       int limitIndex_;
    
    70 78
       int charMapIndex_;
    
    71 79
       double boldX_, boldY_, slant_;
    
    72 80
       double strokeRadius_;
    
    81
    +  double rotation_;
    
    82
    +  bool vertical_;
    
    83
    +  bool waterfall_;
    
    84
    +  QString text_;
    
    73 85
     
    
    74 86
       int displayingCount_ = 0;
    
    75 87
       FT_Size_Metrics metrics_;
    
    76 88
       int x_ = 0, y_ = 0;
    
    77 89
       int stepY_ = 0;
    
    90
    +
    
    91
    +  // Pay especially attention to life cycles & ownerships of those objects:
    
    92
    +  // Note that outline and bitmap can be either invalid, owned by glyph or
    
    93
    +  // owned by `this`.
    
    94
    +  // If owned by `this`, then it's safe to do manipulation, and need to cleanup
    
    95
    +  // If owned by glyph, then must clone to do manipulation, and no cleanup
    
    96
    +  // In `loadGraph`, these 3 values will all be updated.
    
    97
    +  // Note that `glyph_` is a pointer, while `outline_` and `bitmap_` are structs
    
    78 98
       FT_Glyph glyph_;
    
    79
    -  FT_Outline outline_;
    
    99
    +  FT_Outline outline_; // Using outline_->points == NULL to determine validity
    
    100
    +  FT_Bitmap bitmap_; // Using bitmap_->buffer == NULL to determine validity
    
    80 101
       // when glyph is cloned, outline is factually also cloned
    
    81
    -  // but `isOutlineCloned` won't be set!
    
    82
    -  bool isGlyphCloned_ = false, isOutlineCloned_ = false;
    
    102
    +  // never manually clone your outline or you can't easily render it!
    
    103
    +  bool isGlyphCloned_ = false;
    
    104
    +  bool isBitmapCloned_ = false;
    
    83 105
     
    
    84 106
       FT_Stroker stroker_;
    
    85 107
     
    
    86 108
       void paintAG(QPainter* painter);
    
    87
    -  void transformGlyphAGFancy();
    
    88
    -  void transformGlyphAGStroked();
    
    109
    +  void transformGlyphFancy();
    
    110
    +  void transformGlyphStroked();
    
    89 111
       void prePaint();
    
    90 112
       // return if there's enough space to paint the current char
    
    91 113
       bool paintChar(QPainter* painter);
    
    92 114
       bool loadGlyph(int index);
    
    115
    +
    
    93 116
       void cloneGlyph();
    
    94
    -  void cloneOutline();
    
    117
    +  void cloneBitmap();
    
    118
    +  void refreshOutlineOrBitmapFromGlyph();
    
    95 119
       void cleanCloned();
    
    96 120
     
    
    97 121
       bool checkFitX(int x);
    

  • src/ftinspect/rendering/grid.cpp
    ... ... @@ -55,9 +55,6 @@ Grid::updateRect()
    55 55
     }
    
    56 56
     
    
    57 57
     
    
    58
    -// XXX call this in a `myQDraphicsView::drawBackground' derived method
    
    59
    -//     to always fill the complete viewport
    
    60
    -
    
    61 58
     void
    
    62 59
     Grid::paint(QPainter* painter,
    
    63 60
                 const QStyleOptionGraphicsItem* option,
    

  • src/ftinspect/rendering/renderutils.cpp
    ... ... @@ -25,6 +25,19 @@ cloneGlyph(FT_Glyph src)
    25 25
     }
    
    26 26
     
    
    27 27
     
    
    28
    +FT_Bitmap
    
    29
    +cloneBitmap(FT_Library library,
    
    30
    +            FT_Bitmap* src)
    
    31
    +{
    
    32
    +  FT_Bitmap target = *src;
    
    33
    +  target.buffer = NULL;
    
    34
    +  target.palette = NULL;
    
    35
    +  FT_Bitmap_Init(&target);
    
    36
    +  FT_Bitmap_Copy(library, src, &target);
    
    37
    +  return target;
    
    38
    +}
    
    39
    +
    
    40
    +
    
    28 41
     void
    
    29 42
     transformOutlineToOrigin(FT_Outline* outline,
    
    30 43
                              FT_BBox* outControlBox)
    

  • src/ftinspect/rendering/renderutils.hpp
    ... ... @@ -5,11 +5,13 @@
    5 5
     #pragma once
    
    6 6
     
    
    7 7
     #include <freetype/ftglyph.h>
    
    8
    +#include <freetype/ftbitmap.h>
    
    8 9
     #include <freetype/ftoutln.h>
    
    9 10
     
    
    10 11
     // The constructed `outline` must be freed by the caller
    
    11 12
     FT_Outline cloneOutline(FT_Library library, FT_Outline* src);
    
    12 13
     FT_Glyph cloneGlyph(FT_Glyph src);
    
    14
    +FT_Bitmap cloneBitmap(FT_Library library, FT_Bitmap* src);
    
    13 15
     
    
    14 16
     void transformOutlineToOrigin(FT_Outline* outline,
    
    15 17
                                   FT_BBox* outControlBox);
    


  • reply via email to

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