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] [ftinspect] WIP: Add i


From: Charlie Jiang (@cqjjjzr)
Subject: [Git][freetype/freetype-demos][gsoc-2022-chariri] [ftinspect] WIP: Add initial support to "Continuous View".
Date: Sun, 10 Jul 2022 07:12:07 +0000

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

Commits:

  • b1746bda
    by Charlie Jiang at 2022-07-10T15:06:02+08:00
    [ftinspect] WIP: Add initial support to "Continuous View".
    
    This commit adds a tab to the main GUI named "Continuous View",
    corresponding to the `ftview` tool. Inside the tab is a glyph canvas and
    another tab view. The tab view is used to switch modes and input settings..
    
    The rendering canvas is *not* a `QGraphicsView`, but a simple `QWidget` with
    a custom `paintEvent`. This is because we don't need features like panning
    and zooming, so using `QGraphicsView` will only add complexity (e.g.
    transforming coordination systems).
    
    Code translating FreeType outline to the origin for rendering is extracted
    as a helper function in a new "render utils" file.
    
    The font size selector (size, unit, DPI) in the original `SingularTab` is
    extracted as a new class `FontSizeSelector`.
    
    The "graphics defaults", which are graphics objects like color palettes and
    `QPen`s, are all extracted into a new singleton struct `GraphicsDefaults`,
    so every component can easily obtain them.
    
    Currently there're a lot of settings, status variables and parameters during
    the rendering process. Will write some documentation clearifing them all.
    
    WIP: Only "all glyphs" view is implemented.
    TODO: Fancy, Stroked, Text String mode; LCD Anti-Aliasing; Bitmap font;
    
    The rendering code is adopted from singular rendering, which is different
    from the code in `ftcommon.c` from the legacy tools. In the future we may
    need to re-implement this with code from the latter.
    
    * src/ftinspect/rendering/glyphcontinuous.cpp,
      src/ftinspect/rendering/glyphcontinuous.hpp: New file: the actual
      "rendering canvas" in the "Continuous View". The code was a combination of
      `ftcommon` and the singular view's render views. Mouse scrolling is
      supported for navigation and resizing.
    
    * src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
      New files: the content of the "Continuous View" tab is a `ContinuousTab`.
      It current only support one single mode and submode.
    
      Settings about "All Glyphs" mode is placed in `ContinousAllGlyphsTab`.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp: Add
      CharMap handling code, especially `CharMapInfo` struct. `CharMapInfo` can
      provide the name and max index for the charmap. Vector of `CharMapInfo`
      for current font is obtained via `Engine::currentFontCharMaps`.
    
      CharMap mapping is done via `CharMapInfo::glyphIndexFromCharCode`, with
      the added `FTC_CMapCache`.
    
      Add more actions to support continuous view. `reloadFont` and
      `loadGlyphWithoutUpdate` can load fonts and glyphs with minimal overhead.
      `loadGlyphWithoutUpdate` uses `FTC_ImageCache_Lookup`, so the
      `FTC_ImageTypeRec` object is cached.
    
    * src/ftinspect/widgets/fontsizeselector.cpp,
      src/ftinspect/widgets/fontsizeselector.hpp: New file, include the font
      size setting part. It can directly apply settings to the engine via
      `applyToEngine` function, and can handle wheel event from event object or
      by steps count.
    
    * src/ftinspect/widgets/glyphindexselector.cpp,
      src/ftinspect/widgets/glyphindexselector.hpp: Combine `setMax` and
      `setMin` functions, and reduce unnecessary signals by blocking them.
    
      Rename `getCurrentIndex` to `currentIndex`.
    
      Support custom number rendering (for Unicode charcode formatting). Adjust
      layout and disabled wrapping on the spinbox.
    
    * src/ftinspect/rendering/graphicsdefault.cpp,
      src/ftinspect/rendering/graphicsdefault.hpp: New file, including graphics
      initializing code.
    
    * src/ftinspect/rendering/renderutils.cpp,
      src/ftinspect/rendering/renderutils.hpp: New file, including outline
      translating code.
    
    * src/ftinspect/rendering/glyphbitmap.cpp: Move out outline tranlating code.
    
    * src/ftinspect/panels/singular.cpp, src/ftinspect/panels/singular.hpp: Move
      out the font size selector and graphics defaults. Minor change due to
      change in `GlyphIndexSelector`.
    
    * src/ftinspect/maingui.cpp, src/ftinspect/maingui.hpp: Add "Continuous
      View" to tab view.
    
    * src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
    

21 changed files:

Changes:

  • src/ftinspect/CMakeLists.txt
    ... ... @@ -27,15 +27,20 @@ add_executable(ftinspect
    27 27
       "rendering/glyphoutline.cpp"
    
    28 28
       "rendering/glyphpointnumbers.cpp"
    
    29 29
       "rendering/glyphpoints.cpp"
    
    30
    +  "rendering/glyphcontinuous.cpp"
    
    30 31
       "rendering/grid.cpp"
    
    32
    +  "rendering/graphicsdefault.cpp"
    
    33
    +  "rendering/renderutils.cpp"
    
    31 34
     
    
    32 35
       "widgets/customwidgets.cpp"
    
    33 36
       "widgets/glyphindexselector.cpp"
    
    37
    +  "widgets/fontsizeselector.cpp"
    
    34 38
     
    
    35 39
       "models/ttsettingscomboboxmodel.cpp"
    
    36 40
     
    
    37 41
       "panels/settingpanel.cpp"
    
    38 42
       "panels/singular.cpp"
    
    43
    +  "panels/continuous.cpp"
    
    39 44
     )
    
    40 45
     target_link_libraries(ftinspect
    
    41 46
       Qt5::Core Qt5::Widgets
    

  • src/ftinspect/engine/engine.cpp
    ... ... @@ -148,6 +148,12 @@ Engine::Engine()
    148 148
         // XXX error handling
    
    149 149
       }
    
    150 150
     
    
    151
    +  error = FTC_CMapCache_New(cacheManager_, &cmapCache_);
    
    152
    +  if (error)
    
    153
    +  {
    
    154
    +    // XXX error handling
    
    155
    +  }
    
    156
    +
    
    151 157
       queryEngine();
    
    152 158
     }
    
    153 159
     
    
    ... ... @@ -278,6 +284,8 @@ Engine::loadFont(int fontIndex,
    278 284
         }
    
    279 285
       }
    
    280 286
     
    
    287
    +  imageType_.face_id = scaler_.face_id;
    
    288
    +
    
    281 289
       if (numGlyphs < 0)
    
    282 290
       {
    
    283 291
         ftSize_ = NULL;
    
    ... ... @@ -286,16 +294,22 @@ Engine::loadFont(int fontIndex,
    286 294
       }
    
    287 295
       else
    
    288 296
       {
    
    289
    -    curFamilyName_ = QString(ftSize_->face->family_name);
    
    290
    -    curStyleName_ = QString(ftSize_->face->style_name);
    
    297
    +    auto face = ftSize_->face;
    
    298
    +    curFamilyName_ = QString(face->family_name);
    
    299
    +    curStyleName_ = QString(face->style_name);
    
    291 300
     
    
    292
    -    const char* moduleName = FT_FACE_DRIVER_NAME( ftSize_->face );
    
    301
    +    const char* moduleName = FT_FACE_DRIVER_NAME( face );
    
    293 302
     
    
    294 303
         // XXX cover all available modules
    
    295 304
         if (!strcmp(moduleName, "cff"))
    
    296 305
           fontType_ = FontType_CFF;
    
    297 306
         else if (!strcmp(moduleName, "truetype"))
    
    298 307
           fontType_ = FontType_TrueType;
    
    308
    +
    
    309
    +    curCharMaps_.clear();
    
    310
    +    curCharMaps_.reserve(face->num_charmaps);
    
    311
    +    for (int i = 0; i < face->num_charmaps; i++)
    
    312
    +      curCharMaps_.append(CharMapInfo(i, face->charmaps[i]));
    
    299 313
       }
    
    300 314
     
    
    301 315
       curNumGlyphs_ = numGlyphs;
    
    ... ... @@ -303,6 +317,17 @@ Engine::loadFont(int fontIndex,
    303 317
     }
    
    304 318
     
    
    305 319
     
    
    320
    +void
    
    321
    +Engine::reloadFont()
    
    322
    +{
    
    323
    +  update();
    
    324
    +  if (!scaler_.face_id)
    
    325
    +    return;
    
    326
    +  imageType_.face_id = scaler_.face_id;
    
    327
    +  FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_);
    
    328
    +}
    
    329
    +
    
    330
    +
    
    306 331
     void
    
    307 332
     Engine::removeFont(int fontIndex, bool closeFile)
    
    308 333
     {
    
    ... ... @@ -331,6 +356,22 @@ Engine::removeFont(int fontIndex, bool closeFile)
    331 356
     }
    
    332 357
     
    
    333 358
     
    
    359
    +unsigned
    
    360
    +Engine::glyphIndexFromCharCode(int code, int charMapIndex)
    
    361
    +{
    
    362
    +  if (charMapIndex == -1)
    
    363
    +    return code;
    
    364
    +  return FTC_CMapCache_Lookup(cmapCache_, scaler_.face_id, charMapIndex, code);
    
    365
    +}
    
    366
    +
    
    367
    +
    
    368
    +FT_Size_Metrics const&
    
    369
    +Engine::currentFontMetrics()
    
    370
    +{
    
    371
    +  return ftSize_->metrics;
    
    372
    +}
    
    373
    +
    
    374
    +
    
    334 375
     QString
    
    335 376
     Engine::glyphName(int index)
    
    336 377
     {
    
    ... ... @@ -390,6 +431,26 @@ Engine::loadOutline(int glyphIndex)
    390 431
     }
    
    391 432
     
    
    392 433
     
    
    434
    +FT_Glyph
    
    435
    +Engine::loadGlyphWithoutUpdate(int glyphIndex)
    
    436
    +{
    
    437
    +  // TODO bitmap fonts? color layered fonts?
    
    438
    +  FT_Glyph glyph;
    
    439
    +  imageType_.flags |= FT_LOAD_NO_BITMAP;
    
    440
    +  if (FTC_ImageCache_Lookup(imageCache_,
    
    441
    +                            &imageType_,
    
    442
    +                            glyphIndex,
    
    443
    +                            &glyph,
    
    444
    +                            NULL))
    
    445
    +  {
    
    446
    +    // XXX error handling?
    
    447
    +    return NULL;
    
    448
    +  }
    
    449
    +
    
    450
    +  return glyph;
    
    451
    +}
    
    452
    +
    
    453
    +
    
    393 454
     int
    
    394 455
     Engine::numberOfOpenedFonts()
    
    395 456
     {
    
    ... ... @@ -500,6 +561,10 @@ Engine::update()
    500 561
         scaler_.x_res = dpi_;
    
    501 562
         scaler_.y_res = dpi_;
    
    502 563
       }
    
    564
    +  
    
    565
    +  imageType_.width = static_cast<unsigned int>(pixelSize_);
    
    566
    +  imageType_.height = static_cast<unsigned int>(pixelSize_);
    
    567
    +  imageType_.flags = static_cast<int>(loadFlags_);
    
    503 568
     }
    
    504 569
     
    
    505 570
     
    
    ... ... @@ -602,4 +667,136 @@ Engine::queryEngine()
    602 667
       }
    
    603 668
     }
    
    604 669
     
    
    670
    +
    
    671
    +QHash<FT_Encoding, QString> encodingNamesCache;
    
    672
    +QHash<FT_Encoding, QString>&
    
    673
    +encodingNames()
    
    674
    +{
    
    675
    +  if (encodingNamesCache.empty())
    
    676
    +  {
    
    677
    +    encodingNamesCache[static_cast<FT_Encoding>(FT_ENCODING_OTHER)]
    
    678
    +     = "Unknown Encoding";
    
    679
    +    encodingNamesCache[FT_ENCODING_NONE] = "No Encoding";
    
    680
    +    encodingNamesCache[FT_ENCODING_MS_SYMBOL] = "MS Symbol (symb)";
    
    681
    +    encodingNamesCache[FT_ENCODING_UNICODE] = "Unicode (unic)";
    
    682
    +    encodingNamesCache[FT_ENCODING_SJIS] = "Shift JIS (sjis)";
    
    683
    +    encodingNamesCache[FT_ENCODING_PRC] = "PRC/GB 18030 (gb)";
    
    684
    +    encodingNamesCache[FT_ENCODING_BIG5] = "Big5 (big5)";
    
    685
    +    encodingNamesCache[FT_ENCODING_WANSUNG] = "Wansung (wans)";
    
    686
    +    encodingNamesCache[FT_ENCODING_JOHAB] = "Johab (joha)";
    
    687
    +    encodingNamesCache[FT_ENCODING_ADOBE_STANDARD] = "Adobe Standard (ADOB)";
    
    688
    +    encodingNamesCache[FT_ENCODING_ADOBE_EXPERT] = "Adobe Expert (ADBE)";
    
    689
    +    encodingNamesCache[FT_ENCODING_ADOBE_CUSTOM] = "Adobe Custom (ADBC)";
    
    690
    +    encodingNamesCache[FT_ENCODING_ADOBE_LATIN_1] = "Latin 1 (lat1)";
    
    691
    +    encodingNamesCache[FT_ENCODING_OLD_LATIN_2] = "Latin 2 (lat2)";
    
    692
    +    encodingNamesCache[FT_ENCODING_APPLE_ROMAN] = "Apple Roman (armn)";
    
    693
    +  }
    
    694
    +
    
    695
    +  return encodingNamesCache;
    
    696
    +}
    
    697
    +
    
    698
    +
    
    699
    +CharMapInfo::CharMapInfo(int index, FT_CharMap cmap)
    
    700
    +: index(index), ptr(cmap), encoding(cmap->encoding), maxIndex(-1)
    
    701
    +{
    
    702
    +  auto& names = encodingNames();
    
    703
    +  auto it = names.find(encoding);
    
    704
    +  if (it == names.end())
    
    705
    +    encodingName = &names[static_cast<FT_Encoding>(FT_ENCODING_OTHER)];
    
    706
    +  else
    
    707
    +    encodingName = &it.value();
    
    708
    +
    
    709
    +  if (encoding != FT_ENCODING_OTHER)
    
    710
    +    maxIndex = computeMaxIndex();
    
    711
    +}
    
    712
    +
    
    713
    +
    
    714
    +QString
    
    715
    +CharMapInfo::stringifyIndex(int code, int index)
    
    716
    +{
    
    717
    +  return QString("CharCode: %1 (glyph idx %2)")
    
    718
    +           .arg(stringifyIndexShort(code))
    
    719
    +           .arg(index);
    
    720
    +}
    
    721
    +
    
    722
    +
    
    723
    +QString
    
    724
    +CharMapInfo::stringifyIndexShort(int code)
    
    725
    +{
    
    726
    +  return (encoding == FT_ENCODING_UNICODE ? "U+" : "0x")
    
    727
    +         + QString::number(code, 16).rightJustified(4, '0').toUpper();
    
    728
    +}
    
    729
    +
    
    730
    +
    
    731
    +int
    
    732
    +CharMapInfo::computeMaxIndex()
    
    733
    +{
    
    734
    +  int maxIndex = 0;
    
    735
    +  switch (encoding)
    
    736
    +  {
    
    737
    +  case FT_ENCODING_UNICODE:
    
    738
    +    maxIndex = maxIndexForFaceAndCharMap(ptr, 0x110000) + 1;
    
    739
    +    break;
    
    740
    +
    
    741
    +  case FT_ENCODING_ADOBE_LATIN_1:
    
    742
    +  case FT_ENCODING_ADOBE_STANDARD:
    
    743
    +  case FT_ENCODING_ADOBE_EXPERT:
    
    744
    +  case FT_ENCODING_ADOBE_CUSTOM:
    
    745
    +  case FT_ENCODING_APPLE_ROMAN:
    
    746
    +    maxIndex = 0x100;
    
    747
    +    break;
    
    748
    +
    
    749
    +  /* some fonts use range 0x00-0x100, others have 0xF000-0xF0FF */
    
    750
    +  case FT_ENCODING_MS_SYMBOL:
    
    751
    +    maxIndex = maxIndexForFaceAndCharMap(ptr, 0x10000) + 1;
    
    752
    +    break;
    
    753
    +
    
    754
    +  default:
    
    755
    +    // Some encodings can reach > 0x10000, e.g. GB 18030.
    
    756
    +    maxIndex = maxIndexForFaceAndCharMap(ptr, 0x110000) + 1;
    
    757
    +  }
    
    758
    +  return maxIndex;
    
    759
    +}
    
    760
    +
    
    761
    +
    
    762
    +int
    
    763
    +CharMapInfo::maxIndexForFaceAndCharMap(FT_CharMap charMap,
    
    764
    +                                       unsigned max)
    
    765
    +{
    
    766
    +  // code adopted from `ftcommon.c`
    
    767
    +  FT_ULong min = 0;
    
    768
    +  FT_UInt glyphIndex;
    
    769
    +  FT_Face face = charMap->face;
    
    770
    +
    
    771
    +  if (FT_Set_Charmap(face, charMap))
    
    772
    +    return -1;
    
    773
    +
    
    774
    +  do
    
    775
    +  {
    
    776
    +    FT_ULong mid = (min + max) >> 1;
    
    777
    +    FT_ULong res = FT_Get_Next_Char(face, mid, &glyphIndex);
    
    778
    +
    
    779
    +    if (glyphIndex)
    
    780
    +      min = res;
    
    781
    +    else
    
    782
    +    {
    
    783
    +      max = mid;
    
    784
    +
    
    785
    +      // once moved, it helps to advance min through sparse regions
    
    786
    +      if (min)
    
    787
    +      {
    
    788
    +        res = FT_Get_Next_Char(face, min, &glyphIndex);
    
    789
    +
    
    790
    +        if (glyphIndex)
    
    791
    +          min = res;
    
    792
    +        else
    
    793
    +          max = min; // found it
    
    794
    +      }
    
    795
    +    }
    
    796
    +  } while (max > min);
    
    797
    +
    
    798
    +  return static_cast<int>(max);
    
    799
    +}
    
    800
    +
    
    801
    +
    
    605 802
     // end of engine.cpp

  • src/ftinspect/engine/engine.hpp
    ... ... @@ -36,6 +36,29 @@ struct FaceID
    36 36
       bool operator<(const FaceID& other) const;
    
    37 37
     };
    
    38 38
     
    
    39
    +class Engine;
    
    40
    +
    
    41
    +#define FT_ENCODING_OTHER 0xFFFE
    
    42
    +struct CharMapInfo
    
    43
    +{
    
    44
    +  int index;
    
    45
    +  FT_CharMap ptr;
    
    46
    +  FT_Encoding encoding;
    
    47
    +  QString* encodingName;
    
    48
    +
    
    49
    +  // Actually this shouldn't go here, but for convenience...
    
    50
    +  int maxIndex;
    
    51
    +
    
    52
    +  CharMapInfo(int index, FT_CharMap cmap);
    
    53
    +
    
    54
    +  QString stringifyIndex(int code, int index);
    
    55
    +  QString stringifyIndexShort(int code);
    
    56
    +
    
    57
    +private:
    
    58
    +  int computeMaxIndex();
    
    59
    +  static int maxIndexForFaceAndCharMap(FT_CharMap charMap, unsigned max);
    
    60
    +};
    
    61
    +
    
    39 62
     // FreeType specific data.
    
    40 63
     
    
    41 64
     class Engine
    
    ... ... @@ -70,6 +93,13 @@ public:
    70 93
                    int namedInstanceIndex); // return number of glyphs
    
    71 94
       FT_Outline* loadOutline(int glyphIndex);
    
    72 95
     
    
    96
    +  // Sometimes the engine is already updated, and we want to be faster
    
    97
    +  FT_Glyph loadGlyphWithoutUpdate(int glyphIndex);
    
    98
    +
    
    99
    +  // reload current triplet, but with updated settings, useful for updating
    
    100
    +  // `ftSize_` only
    
    101
    +  void reloadFont(); 
    
    102
    +
    
    73 103
       void openFonts(QStringList fontFileNames);
    
    74 104
       void removeFont(int fontIndex, bool closeFile = true);
    
    75 105
       
    
    ... ... @@ -87,14 +117,16 @@ public:
    87 117
       long numberOfFaces(int fontIndex);
    
    88 118
       int numberOfNamedInstances(int fontIndex,
    
    89 119
                                  long faceIndex);
    
    120
    +  // Note: the current font face must be properly set
    
    121
    +  unsigned glyphIndexFromCharCode(int code, int charMapIndex);
    
    122
    +  FT_Size_Metrics const& currentFontMetrics();
    
    90 123
     
    
    91
    -  // XXX We should prepend '_' to all private member variable so we can create
    
    92
    -  // getter without naming conflict... e.g. var named _fontFileManager while
    
    93
    -  // getter named fontFileManager
    
    124
    +  QVector<CharMapInfo>& currentFontCharMaps() { return curCharMaps_; }
    
    94 125
       FontFileManager& fontFileManager() { return fontFileManager_; }
    
    95 126
       EngineDefaultValues& engineDefaults() { return engineDefaults_; }
    
    96 127
       bool antiAliasingEnabled() { return antiAliasingEnabled_; }
    
    97 128
     
    
    129
    +
    
    98 130
       //////// Setters (direct or indirect)
    
    99 131
     
    
    100 132
       void setDPI(int d) { dpi_ = d; }
    
    ... ... @@ -142,14 +174,17 @@ private:
    142 174
       QString curFamilyName_;
    
    143 175
       QString curStyleName_;
    
    144 176
       int curNumGlyphs_ = -1;
    
    177
    +  QVector<CharMapInfo> curCharMaps_;
    
    145 178
     
    
    146 179
       FT_Library library_;
    
    147 180
       FTC_Manager cacheManager_;
    
    148 181
       FTC_ImageCache imageCache_;
    
    149 182
       FTC_SBitCache sbitsCache_;
    
    183
    +  FTC_CMapCache cmapCache_;
    
    150 184
     
    
    151 185
       FTC_ScalerRec scaler_;
    
    152 186
       FT_Size ftSize_;
    
    187
    +  FTC_ImageTypeRec imageType_;
    
    153 188
     
    
    154 189
       EngineDefaultValues engineDefaults_;
    
    155 190
     
    

  • src/ftinspect/maingui.cpp
    ... ... @@ -15,6 +15,8 @@
    15 15
     
    
    16 16
     #include <freetype/ftdriver.h>
    
    17 17
     
    
    18
    +#include "panels/continuous.hpp"
    
    19
    +
    
    18 20
     
    
    19 21
     MainGUI::MainGUI(Engine* engine)
    
    20 22
     : engine_(engine)
    
    ... ... @@ -448,12 +450,15 @@ MainGUI::createLayout()
    448 450
       fontNameLabel_ = new QLabel(this);
    
    449 451
     
    
    450 452
       singularTab_ = new SingularTab(this, engine_);
    
    453
    +  continuousTab_ = new ContinuousTab(this, engine_);
    
    451 454
     
    
    452 455
       tabWidget_ = new QTabWidget(this);
    
    453 456
     
    
    454 457
       // Note those two list must be in sync
    
    455 458
       tabs_.append(singularTab_);
    
    456 459
       tabWidget_->addTab(singularTab_, tr("Singular Grid View"));
    
    460
    +  tabs_.append(continuousTab_);
    
    461
    +  tabWidget_->addTab(continuousTab_, tr("Continuous View"));
    
    457 462
     
    
    458 463
       previousFontButton_ = new QPushButton(tr("Previous Font"), this);
    
    459 464
       nextFontButton_ = new QPushButton(tr("Next Font"), this);
    
    ... ... @@ -504,6 +509,9 @@ MainGUI::createConnections()
    504 509
       connect(settingPanel_, &SettingPanel::repaintNeeded,
    
    505 510
               this, &MainGUI::repaintCurrentTab);
    
    506 511
     
    
    512
    +  connect(tabWidget_, &QTabWidget::currentChanged,
    
    513
    +          this, &MainGUI::reloadCurrentTabFont);
    
    514
    +
    
    507 515
       connect(previousFontButton_, &QPushButton::clicked,
    
    508 516
               this, &MainGUI::previousFont);
    
    509 517
       connect(nextFontButton_, &QPushButton::clicked,
    

  • src/ftinspect/maingui.hpp
    ... ... @@ -11,6 +11,7 @@
    11 11
     #include "models/ttsettingscomboboxmodel.hpp"
    
    12 12
     #include "panels/settingpanel.hpp"
    
    13 13
     #include "panels/singular.hpp"
    
    14
    +#include "panels/continuous.hpp"
    
    14 15
     
    
    15 16
     #include <QAction>
    
    16 17
     #include <QCheckBox>
    
    ... ... @@ -136,6 +137,7 @@ private:
    136 137
       QTabWidget* tabWidget_;
    
    137 138
       QVector<AbstractTab*> tabs_;
    
    138 139
       SingularTab* singularTab_;
    
    140
    +  ContinuousTab* continuousTab_;
    
    139 141
     
    
    140 142
       void openFonts(QStringList const& fileNames);
    
    141 143
     
    

  • src/ftinspect/meson.build
    ... ... @@ -27,14 +27,19 @@ if qt5_dep.found()
    27 27
         'rendering/glyphoutline.cpp',
    
    28 28
         'rendering/glyphpointnumbers.cpp',
    
    29 29
         'rendering/glyphpoints.cpp',
    
    30
    +    'rendering/glyphcontinuous.cpp',
    
    30 31
         'rendering/grid.cpp',
    
    32
    +    'rendering/graphicsdefault.cpp',
    
    33
    +    'rendering/renderutils.cpp',
    
    31 34
         'widgets/customwidgets.cpp',
    
    32 35
         'widgets/glyphindexselector.cpp',
    
    36
    +    'widgets/fontsizeselector.cpp',
    
    33 37
     
    
    34 38
         'models/ttsettingscomboboxmodel.cpp',
    
    35 39
     
    
    36 40
         'panels/settingpanel.cpp',
    
    37 41
         'panels/singular.cpp',
    
    42
    +    'panels/continuous.cpp',
    
    38 43
     
    
    39 44
         'ftinspect.cpp',
    
    40 45
         'maingui.cpp',
    
    ... ... @@ -46,9 +51,12 @@ if qt5_dep.found()
    46 51
           'engine/fontfilemanager.hpp',
    
    47 52
           'widgets/customwidgets.hpp',
    
    48 53
           'widgets/glyphindexselector.hpp',
    
    54
    +      'widgets/fontsizeselector.hpp',
    
    55
    +      'widgets/glyphcontinuous.hpp',
    
    49 56
           'models/ttsettingscomboboxmodel.hpp',
    
    50 57
           'panels/settingpanel.hpp',
    
    51 58
           'panels/singular.hpp',
    
    59
    +      'panels/continuous.hpp',
    
    52 60
           'maingui.hpp',
    
    53 61
         ],
    
    54 62
         dependencies: qt5_dep)
    

  • src/ftinspect/panels/continuous.cpp
    1
    +// continuous.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "continuous.hpp"
    
    6
    +
    
    7
    +#include <climits>
    
    8
    +#include <QVariant>
    
    9
    +
    
    10
    +
    
    11
    +ContinuousTab::ContinuousTab(QWidget* parent,
    
    12
    +                             Engine* engine)
    
    13
    +: QWidget(parent), engine_(engine)
    
    14
    +{
    
    15
    +  createLayout();
    
    16
    +  createConnections();
    
    17
    +}
    
    18
    +
    
    19
    +
    
    20
    +void
    
    21
    +ContinuousTab::repaintGlyph()
    
    22
    +{
    
    23
    +  sizeSelector_->applyToEngine(engine_);
    
    24
    +  
    
    25
    +  updateFromCurrentSubTab();
    
    26
    +  canvas_->repaint();
    
    27
    +}
    
    28
    +
    
    29
    +
    
    30
    +void
    
    31
    +ContinuousTab::reloadFont()
    
    32
    +{
    
    33
    +  currentGlyphCount_ = engine_->currentFontNumberOfGlyphs();
    
    34
    +  updateCurrentSubTab();
    
    35
    +  repaintGlyph();
    
    36
    +}
    
    37
    +
    
    38
    +
    
    39
    +void
    
    40
    +ContinuousTab::syncSettings()
    
    41
    +{
    
    42
    +}
    
    43
    +
    
    44
    +
    
    45
    +void
    
    46
    +ContinuousTab::changeTab()
    
    47
    +{
    
    48
    +  updateCurrentSubTab();
    
    49
    +  repaintGlyph();
    
    50
    +}
    
    51
    +
    
    52
    +
    
    53
    +void
    
    54
    +ContinuousTab::wheelNavigate(int steps)
    
    55
    +{
    
    56
    +  if (tabWidget_->currentIndex() == AllGlyphs)
    
    57
    +    allGlyphsTab_->setGlyphBeginindex(allGlyphsTab_->glyphBeginindex()
    
    58
    +                                      + steps);
    
    59
    +}
    
    60
    +
    
    61
    +
    
    62
    +void
    
    63
    +ContinuousTab::wheelResize(int steps)
    
    64
    +{
    
    65
    +  sizeSelector_->handleWheelResizeBySteps(steps);
    
    66
    +}
    
    67
    +
    
    68
    +
    
    69
    +void
    
    70
    +ContinuousTab::createLayout()
    
    71
    +{
    
    72
    +  canvas_ = new GlyphContinuous(this, engine_);
    
    73
    +  sizeSelector_ = new FontSizeSelector(this);
    
    74
    +  allGlyphsTab_ = new ContinousAllGlyphsTab(this);
    
    75
    +
    
    76
    +  tabWidget_ = new QTabWidget(this);
    
    77
    +  tabWidget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    78
    +  // Must be in sync with `Tabs` enum.
    
    79
    +  tabWidget_->addTab(allGlyphsTab_, tr("All Glyphs"));
    
    80
    +
    
    81
    +  mainLayout_ = new QVBoxLayout;
    
    82
    +  mainLayout_->addWidget(canvas_);
    
    83
    +  mainLayout_->addWidget(sizeSelector_);
    
    84
    +  mainLayout_->addWidget(tabWidget_);
    
    85
    +
    
    86
    +  setLayout(mainLayout_);
    
    87
    +}
    
    88
    +
    
    89
    +
    
    90
    +void
    
    91
    +ContinuousTab::createConnections()
    
    92
    +{
    
    93
    +  connect(tabWidget_, &QTabWidget::currentChanged,
    
    94
    +          this, &ContinuousTab::changeTab);
    
    95
    +
    
    96
    +  connect(allGlyphsTab_, &ContinousAllGlyphsTab::changed, 
    
    97
    +          this, &ContinuousTab::repaintGlyph);
    
    98
    +
    
    99
    +  connect(sizeSelector_, &FontSizeSelector::valueChanged,
    
    100
    +          this, &ContinuousTab::repaintGlyph);
    
    101
    +
    
    102
    +  connect(canvas_, &GlyphContinuous::wheelResize, 
    
    103
    +          this, &ContinuousTab::wheelResize);
    
    104
    +  connect(canvas_, &GlyphContinuous::wheelNavigate, 
    
    105
    +          this, &ContinuousTab::wheelNavigate);
    
    106
    +  connect(canvas_, &GlyphContinuous::displayingCountUpdated, 
    
    107
    +          allGlyphsTab_, &ContinousAllGlyphsTab::setDisplayingCount);
    
    108
    +}
    
    109
    +
    
    110
    +
    
    111
    +void
    
    112
    +ContinuousTab::setDefaults()
    
    113
    +{
    
    114
    +}
    
    115
    +
    
    116
    +
    
    117
    +void
    
    118
    +ContinuousTab::updateCurrentSubTab()
    
    119
    +{
    
    120
    +  switch (tabWidget_->currentIndex())
    
    121
    +  {
    
    122
    +  case AllGlyphs:
    
    123
    +    allGlyphsTab_->setGlyphCount(qBound(0, 
    
    124
    +                                        currentGlyphCount_,
    
    125
    +                                        INT_MAX));
    
    126
    +    allGlyphsTab_->setCharMaps(engine_->currentFontCharMaps());
    
    127
    +    break;
    
    128
    +  }
    
    129
    +}
    
    130
    +
    
    131
    +
    
    132
    +void
    
    133
    +ContinuousTab::updateFromCurrentSubTab()
    
    134
    +{
    
    135
    +  switch (tabWidget_->currentIndex())
    
    136
    +  {
    
    137
    +  case AllGlyphs:
    
    138
    +    // Begin index is selected from All Glyphs subtab,
    
    139
    +    // and Limit index is calculated by All Glyphs subtab
    
    140
    +    canvas_->setBeginIndex(allGlyphsTab_->glyphBeginindex());
    
    141
    +    canvas_->setLimitIndex(allGlyphsTab_->glyphLimitIndex());
    
    142
    +    canvas_->setMode(GlyphContinuous::AllGlyphs);
    
    143
    +    canvas_->setSubModeAllGlyphs(allGlyphsTab_->subMode());
    
    144
    +    canvas_->setCharMapIndex(allGlyphsTab_->charMapIndex());
    
    145
    +    break;
    
    146
    +  }
    
    147
    +}
    
    148
    +
    
    149
    +
    
    150
    +ContinousAllGlyphsTab::ContinousAllGlyphsTab(QWidget* parent)
    
    151
    +: QWidget(parent)
    
    152
    +{
    
    153
    +  createLayout();
    
    154
    +
    
    155
    +  QVector<CharMapInfo> tempCharMaps;
    
    156
    +  setCharMaps(tempCharMaps); // pass in an empty one
    
    157
    +
    
    158
    +  createConnections();
    
    159
    +}
    
    160
    +
    
    161
    +
    
    162
    +int
    
    163
    +ContinousAllGlyphsTab::glyphBeginindex()
    
    164
    +{
    
    165
    +  return indexSelector_->currentIndex();
    
    166
    +}
    
    167
    +
    
    168
    +
    
    169
    +int
    
    170
    +ContinousAllGlyphsTab::glyphLimitIndex()
    
    171
    +{
    
    172
    +  return glyphLimitIndex_;
    
    173
    +}
    
    174
    +
    
    175
    +
    
    176
    +GlyphContinuous::SubModeAllGlyphs
    
    177
    +ContinousAllGlyphsTab::subMode()
    
    178
    +{
    
    179
    +  return static_cast<GlyphContinuous::SubModeAllGlyphs>(
    
    180
    +           modeSelector_->currentIndex());
    
    181
    +}
    
    182
    +
    
    183
    +
    
    184
    +int
    
    185
    +ContinousAllGlyphsTab::charMapIndex()
    
    186
    +{
    
    187
    +  auto index = charMapSelector_->currentIndex() - 1;
    
    188
    +  if (index <= -1)
    
    189
    +    return -1;
    
    190
    +  if (index >= charMaps_.size())
    
    191
    +    return -1;
    
    192
    +  return index;
    
    193
    +}
    
    194
    +
    
    195
    +
    
    196
    +void
    
    197
    +ContinousAllGlyphsTab::setGlyphBeginindex(int index)
    
    198
    +{
    
    199
    +  indexSelector_->setCurrentIndex(index);
    
    200
    +  updateCharMapLimit();
    
    201
    +}
    
    202
    +
    
    203
    +
    
    204
    +void
    
    205
    +ContinousAllGlyphsTab::setDisplayingCount(int count)
    
    206
    +{
    
    207
    +  indexSelector_->setShowingCount(count);
    
    208
    +}
    
    209
    +
    
    210
    +
    
    211
    +#define EncodingRole (Qt::UserRole + 10)
    
    212
    +void
    
    213
    +ContinousAllGlyphsTab::setCharMaps(QVector<CharMapInfo>& charMaps)
    
    214
    +{
    
    215
    +  charMaps_ = charMaps;
    
    216
    +  int oldIndex = charMapSelector_->currentIndex();
    
    217
    +  unsigned oldEncoding = 0u;
    
    218
    +
    
    219
    +  // Using additional UserRole to store encoding id
    
    220
    +  auto oldEncodingV = charMapSelector_->itemData(oldIndex, EncodingRole);
    
    221
    +  if (oldEncodingV.isValid() && oldEncodingV.canConvert<unsigned>())
    
    222
    +  {
    
    223
    +    oldEncoding = oldEncodingV.value<unsigned>();
    
    224
    +  }
    
    225
    +
    
    226
    +  {
    
    227
    +    // suppress events during updating
    
    228
    +    QSignalBlocker selectorBlocker(charMapSelector_);
    
    229
    +
    
    230
    +    charMapSelector_->clear();
    
    231
    +    charMapSelector_->addItem(tr("Glyph Order"));
    
    232
    +    charMapSelector_->setItemData(0, 0u, EncodingRole);
    
    233
    +
    
    234
    +    int i = 0;
    
    235
    +    int newIndex = 0;
    
    236
    +    for (auto& map : charMaps)
    
    237
    +    {
    
    238
    +      charMapSelector_->addItem(tr("%1: %2")
    
    239
    +                                .arg(i)
    
    240
    +                                .arg(*map.encodingName));
    
    241
    +      auto encoding = static_cast<unsigned>(map.encoding);
    
    242
    +      charMapSelector_->setItemData(i, encoding, EncodingRole);
    
    243
    +
    
    244
    +      if (encoding == oldEncoding && i == oldIndex)
    
    245
    +        newIndex = i;
    
    246
    +    
    
    247
    +      i++;
    
    248
    +    }
    
    249
    +
    
    250
    +    // this shouldn't emit any event either, because force repainting
    
    251
    +    // will happen later, so embrace it into blocker block
    
    252
    +    charMapSelector_->setCurrentIndex(newIndex);
    
    253
    +  }
    
    254
    +
    
    255
    +  updateCharMapLimit();
    
    256
    +}
    
    257
    +
    
    258
    +
    
    259
    +void
    
    260
    +ContinousAllGlyphsTab::updateCharMapLimit()
    
    261
    +{
    
    262
    +  if (charMapSelector_->currentIndex() <= 0)
    
    263
    +    glyphLimitIndex_ = currentGlyphCount_;
    
    264
    +  else
    
    265
    +    glyphLimitIndex_
    
    266
    +      = charMaps_[charMapSelector_->currentIndex() - 1].maxIndex + 1;
    
    267
    +  indexSelector_->setMinMax(0, glyphLimitIndex_ - 1);
    
    268
    +}
    
    269
    +
    
    270
    +
    
    271
    +void
    
    272
    +ContinousAllGlyphsTab::createLayout()
    
    273
    +{
    
    274
    +  indexSelector_ = new GlyphIndexSelector(this);
    
    275
    +  indexSelector_->setSingleMode(false);
    
    276
    +  indexSelector_->setNumberRenderer([this](int index)
    
    277
    +                                    { return formatIndex(index); });
    
    278
    +
    
    279
    +  modeSelector_ = new QComboBox(this);
    
    280
    +  charMapSelector_ = new QComboBox(this);
    
    281
    +
    
    282
    +  // Note: in sync with the enum!!
    
    283
    +  modeSelector_->insertItem(GlyphContinuous::AG_AllGlyphs, tr("All Glyphs"));
    
    284
    +  modeSelector_->insertItem(GlyphContinuous::AG_Fancy, tr("Fancy"));
    
    285
    +  modeSelector_->insertItem(GlyphContinuous::AG_Stroked, tr("Stroked"));
    
    286
    +  modeSelector_->insertItem(GlyphContinuous::AG_Waterfall, tr("Waterfall"));
    
    287
    +  modeSelector_->setCurrentIndex(GlyphContinuous::AG_AllGlyphs);
    
    288
    +
    
    289
    +  modeLabel_ = new QLabel(tr("Mode:"), this);
    
    290
    +  charMapLabel_ = new QLabel(tr("Char Map:"), this);
    
    291
    +
    
    292
    +  layout_ = new QGridLayout;
    
    293
    +  layout_->addWidget(indexSelector_, 0, 0, 1, 2);
    
    294
    +  layout_->addWidget(modeLabel_, 1, 0);
    
    295
    +  layout_->addWidget(charMapLabel_, 2, 0);
    
    296
    +  layout_->addWidget(modeSelector_, 1, 1);
    
    297
    +  layout_->addWidget(charMapSelector_, 2, 1);
    
    298
    +
    
    299
    +  layout_->setColumnStretch(1, 1);
    
    300
    +
    
    301
    +  setLayout(layout_);
    
    302
    +}
    
    303
    +
    
    304
    +void
    
    305
    +ContinousAllGlyphsTab::createConnections()
    
    306
    +{
    
    307
    +  connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
    
    308
    +          this, &ContinousAllGlyphsTab::changed);
    
    309
    +  connect(modeSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    310
    +          this, &ContinousAllGlyphsTab::changed);
    
    311
    +  connect(charMapSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    312
    +          this, &ContinousAllGlyphsTab::charMapChanged);
    
    313
    +}
    
    314
    +
    
    315
    +
    
    316
    +QString
    
    317
    +ContinousAllGlyphsTab::formatIndex(int index)
    
    318
    +{
    
    319
    +  if (charMapSelector_->currentIndex() <= 0) // glyph order
    
    320
    +    return QString::number(index);
    
    321
    +  return charMaps_[charMapSelector_->currentIndex() - 1]
    
    322
    +           .stringifyIndexShort(index);
    
    323
    +}
    
    324
    +
    
    325
    +
    
    326
    +void
    
    327
    +ContinousAllGlyphsTab::charMapChanged()
    
    328
    +{
    
    329
    +  int newIndex = charMapSelector_->currentIndex();
    
    330
    +  if (newIndex != lastCharMapIndex_)
    
    331
    +  {
    
    332
    +    if (newIndex <= 0 || charMaps_.size() <= newIndex - 1)
    
    333
    +      setGlyphBeginindex(0);
    
    334
    +    else if (charMaps_[newIndex - 1].maxIndex <= 20)
    
    335
    +      setGlyphBeginindex(charMaps_[newIndex - 1].maxIndex - 1);
    
    336
    +    else
    
    337
    +      setGlyphBeginindex(0x20);
    
    338
    +  }
    
    339
    +  updateCharMapLimit();
    
    340
    +
    
    341
    +  emit changed();
    
    342
    +
    
    343
    +  lastCharMapIndex_ = newIndex;
    
    344
    +}
    
    345
    +
    
    346
    +
    
    347
    +// end of continuous.cpp

  • src/ftinspect/panels/continuous.hpp
    1
    +// continuous.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 "../rendering/graphicsdefault.hpp"
    
    12
    +#include "../rendering/glyphcontinuous.hpp"
    
    13
    +#include "../engine/engine.hpp"
    
    14
    +
    
    15
    +#include <QWidget>
    
    16
    +#include <QLabel>
    
    17
    +#include <QComboBox>
    
    18
    +#include <QVector>
    
    19
    +#include <QGridLayout>
    
    20
    +#include <QBoxLayout>
    
    21
    +
    
    22
    +class ContinousAllGlyphsTab;
    
    23
    +
    
    24
    +class ContinuousTab
    
    25
    +: public QWidget, public AbstractTab
    
    26
    +{
    
    27
    +  Q_OBJECT
    
    28
    +public:
    
    29
    +  ContinuousTab(QWidget* parent, Engine* engine);
    
    30
    +  ~ContinuousTab() override = default;
    
    31
    +
    
    32
    +  void repaintGlyph() override;
    
    33
    +  void reloadFont() override;
    
    34
    +  void syncSettings() override;
    
    35
    +  void setDefaults() override;
    
    36
    +
    
    37
    +  // Info about current font (glyph count, charmaps...) is flowed to subtab
    
    38
    +  // via `updateCurrentSubTab`.
    
    39
    +  // Settings and parameters (e.g. mode) are flowed from subtab to `this` via
    
    40
    +  // `updateFromCurrentSubTab`.
    
    41
    +  // SubTabs can notify `this` via signals, see `createConnections`
    
    42
    +  void updateCurrentSubTab();
    
    43
    +  void updateFromCurrentSubTab();
    
    44
    +
    
    45
    +private slots:
    
    46
    +  void changeTab();
    
    47
    +  void wheelNavigate(int steps);
    
    48
    +  void wheelResize(int steps);
    
    49
    +
    
    50
    +private:
    
    51
    +  Engine* engine_;
    
    52
    +
    
    53
    +  int currentGlyphCount_;
    
    54
    +  GlyphContinuous* canvas_;
    
    55
    +  
    
    56
    +  FontSizeSelector* sizeSelector_;
    
    57
    +
    
    58
    +  QTabWidget* tabWidget_;
    
    59
    +  ContinousAllGlyphsTab* allGlyphsTab_;
    
    60
    +
    
    61
    +  enum Tabs
    
    62
    +  {
    
    63
    +    AllGlyphs = 0
    
    64
    +  };
    
    65
    +
    
    66
    +  QVBoxLayout* mainLayout_;
    
    67
    +  
    
    68
    +  void createLayout();
    
    69
    +  void createConnections();
    
    70
    +};
    
    71
    +
    
    72
    +
    
    73
    +class ContinousAllGlyphsTab
    
    74
    +: public QWidget
    
    75
    +{
    
    76
    +  Q_OBJECT
    
    77
    +public:
    
    78
    +  explicit ContinousAllGlyphsTab(QWidget* parent);
    
    79
    +  ~ContinousAllGlyphsTab() override = default;
    
    80
    +
    
    81
    +  int glyphBeginindex();
    
    82
    +  int glyphLimitIndex();
    
    83
    +  GlyphContinuous::SubModeAllGlyphs subMode();
    
    84
    +
    
    85
    +  // -1: Glyph order, otherwise the char map index in the original list
    
    86
    +  int charMapIndex();
    
    87
    +  void setGlyphBeginindex(int index);
    
    88
    +
    
    89
    +  // This doesn't trigger immediate repaint
    
    90
    +  void setGlyphCount(int count) { currentGlyphCount_ = count; }
    
    91
    +  void setDisplayingCount(int count);
    
    92
    +
    
    93
    +  void setCharMaps(QVector<CharMapInfo>& charMaps);
    
    94
    +  // This doesn't trigger either.
    
    95
    +  void updateCharMapLimit();
    
    96
    +
    
    97
    +signals:
    
    98
    +  void changed();
    
    99
    +
    
    100
    +private:
    
    101
    +  int lastCharMapIndex_ = 0;
    
    102
    +  int currentGlyphCount_;
    
    103
    +  int glyphLimitIndex_ = 0;
    
    104
    +
    
    105
    +  GlyphIndexSelector* indexSelector_;
    
    106
    +  QComboBox* modeSelector_;
    
    107
    +  QComboBox* charMapSelector_;
    
    108
    +
    
    109
    +  QLabel* modeLabel_;
    
    110
    +  QLabel* charMapLabel_;
    
    111
    +
    
    112
    +  QGridLayout* layout_;
    
    113
    +
    
    114
    +  QVector<CharMapInfo> charMaps_;
    
    115
    +
    
    116
    +  void createLayout();
    
    117
    +  void createConnections();
    
    118
    +
    
    119
    +  QString formatIndex(int index);
    
    120
    +  void charMapChanged();
    
    121
    +};
    
    122
    +
    
    123
    +
    
    124
    +// end of continuous.hpp

  • src/ftinspect/panels/singular.cpp
    ... ... @@ -9,15 +9,14 @@
    9 9
     
    
    10 10
     
    
    11 11
     SingularTab::SingularTab(QWidget* parent, Engine* engine)
    
    12
    -: QWidget(parent), engine_(engine)
    
    12
    +: QWidget(parent), engine_(engine),
    
    13
    +  graphicsDefault_(GraphicsDefault::deafultInstance())
    
    13 14
     {
    
    14
    -  setGraphicsDefaults();
    
    15 15
       createLayout();
    
    16 16
       createConnections();
    
    17 17
     
    
    18 18
       currentGlyphIndex_ = 0;
    
    19 19
       checkShowPoints();
    
    20
    -  checkUnits();
    
    21 20
     }
    
    22 21
     
    
    23 22
     
    
    ... ... @@ -97,30 +96,35 @@ SingularTab::drawGlyph()
    97 96
           if (!engine_->antiAliasingEnabled())
    
    98 97
             pixelMode = FT_PIXEL_MODE_MONO;
    
    99 98
     
    
    100
    -      currentGlyphBitmapItem_ = new GlyphBitmap(outline,
    
    101
    -                                               engine_->ftLibrary(),
    
    102
    -                                               pixelMode,
    
    103
    -                                               monoColorTable_,
    
    104
    -                                               grayColorTable_);
    
    99
    +      currentGlyphBitmapItem_
    
    100
    +        = new GlyphBitmap(outline,
    
    101
    +          engine_->ftLibrary(),
    
    102
    +          pixelMode,
    
    103
    +          graphicsDefault_->monoColorTable,
    
    104
    +          graphicsDefault_->grayColorTable);
    
    105 105
           glyphScene_->addItem(currentGlyphBitmapItem_);
    
    106 106
         }
    
    107 107
     
    
    108 108
         if (showOutlinesCheckBox_->isChecked())
    
    109 109
         {
    
    110
    -      currentGlyphOutlineItem_ = new GlyphOutline(outlinePen_, outline);
    
    110
    +      currentGlyphOutlineItem_ = new GlyphOutline(graphicsDefault_->outlinePen, 
    
    111
    +                                                  outline);
    
    111 112
           glyphScene_->addItem(currentGlyphOutlineItem_);
    
    112 113
         }
    
    113 114
     
    
    114 115
         if (showPointsCheckBox_->isChecked())
    
    115 116
         {
    
    116
    -      currentGlyphPointsItem_ = new GlyphPoints(onPen_, offPen_, outline);
    
    117
    +      currentGlyphPointsItem_ = new GlyphPoints(graphicsDefault_->onPen,
    
    118
    +                                                graphicsDefault_->offPen,
    
    119
    +                                                outline);
    
    117 120
           glyphScene_->addItem(currentGlyphPointsItem_);
    
    118 121
     
    
    119 122
           if (showPointNumbersCheckBox_->isChecked())
    
    120 123
           {
    
    121
    -        currentGlyphPointNumbersItem_ = new GlyphPointNumbers(onPen_,
    
    122
    -                                                             offPen_,
    
    123
    -                                                             outline);
    
    124
    +        currentGlyphPointNumbersItem_
    
    125
    +          = new GlyphPointNumbers(graphicsDefault_->onPen,
    
    126
    +                                  graphicsDefault_->offPen,
    
    127
    +                                  outline);
    
    124 128
             glyphScene_->addItem(currentGlyphPointNumbersItem_);
    
    125 129
           }
    
    126 130
         }
    
    ... ... @@ -130,29 +134,6 @@ SingularTab::drawGlyph()
    130 134
     }
    
    131 135
     
    
    132 136
     
    
    133
    -void
    
    134
    -SingularTab::checkUnits()
    
    135
    -{
    
    136
    -  int index = unitsComboBox_->currentIndex();
    
    137
    -
    
    138
    -  if (index == Units_px)
    
    139
    -  {
    
    140
    -    dpiLabel_->setEnabled(false);
    
    141
    -    dpiSpinBox_->setEnabled(false);
    
    142
    -    sizeDoubleSpinBox_->setSingleStep(1);
    
    143
    -    sizeDoubleSpinBox_->setValue(qRound(sizeDoubleSpinBox_->value()));
    
    144
    -  }
    
    145
    -  else
    
    146
    -  {
    
    147
    -    dpiLabel_->setEnabled(true);
    
    148
    -    dpiSpinBox_->setEnabled(true);
    
    149
    -    sizeDoubleSpinBox_->setSingleStep(0.5);
    
    150
    -  }
    
    151
    -
    
    152
    -  drawGlyph();
    
    153
    -}
    
    154
    -
    
    155
    -
    
    156 137
     void
    
    157 138
     SingularTab::checkShowPoints()
    
    158 139
     {
    
    ... ... @@ -219,11 +200,7 @@ SingularTab::wheelZoom(QWheelEvent* event)
    219 200
     void
    
    220 201
     SingularTab::wheelResize(QWheelEvent* event)
    
    221 202
     {
    
    222
    -  int numSteps = event->angleDelta().y() / 120;
    
    223
    -  double sizeAfter = sizeDoubleSpinBox_->value() + numSteps * 0.5;
    
    224
    -  sizeAfter = std::max(sizeDoubleSpinBox_->minimum(),
    
    225
    -                       std::min(sizeAfter, sizeDoubleSpinBox_->maximum()));
    
    226
    -  sizeDoubleSpinBox_->setValue(sizeAfter);
    
    203
    +  sizeSelector_->handleWheelResizeFromGrid(event);
    
    227 204
     }
    
    228 205
     
    
    229 206
     
    
    ... ... @@ -246,7 +223,8 @@ SingularTab::createLayout()
    246 223
       glyphView_->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    
    247 224
       glyphView_->setScene(glyphScene_);
    
    248 225
     
    
    249
    -  gridItem_ = new Grid(glyphView_, gridPen_, axisPen_);
    
    226
    +  gridItem_ = new Grid(glyphView_, graphicsDefault_->gridPen, 
    
    227
    +                       graphicsDefault_->axisPen);
    
    250 228
       glyphScene_->addItem(gridItem_);
    
    251 229
     
    
    252 230
       // Don't use QGraphicsTextItem: We want this hint to be anchored at the
    
    ... ... @@ -271,27 +249,10 @@ SingularTab::createLayout()
    271 249
       glyphIndexLabel_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    272 250
       glyphNameLabel_->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    
    273 251
     
    
    274
    -  sizeLabel_ = new QLabel(tr("Size "), this);
    
    275
    -  sizeLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    276
    -  sizeDoubleSpinBox_ = new QDoubleSpinBox;
    
    277
    -  sizeDoubleSpinBox_->setAlignment(Qt::AlignRight);
    
    278
    -  sizeDoubleSpinBox_->setDecimals(1);
    
    279
    -  sizeDoubleSpinBox_->setRange(1, 500);
    
    280
    -  sizeLabel_->setBuddy(sizeDoubleSpinBox_);
    
    281
    -
    
    282 252
       indexSelector_ = new GlyphIndexSelector(this);
    
    283 253
       indexSelector_->setSingleMode(true);
    
    284 254
     
    
    285
    -  unitsComboBox_ = new QComboBox(this);
    
    286
    -  unitsComboBox_->insertItem(Units_px, "px");
    
    287
    -  unitsComboBox_->insertItem(Units_pt, "pt");
    
    288
    -
    
    289
    -  dpiLabel_ = new QLabel(tr("DPI "), this);
    
    290
    -  dpiLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    291
    -  dpiSpinBox_ = new QSpinBox(this);
    
    292
    -  dpiSpinBox_->setAlignment(Qt::AlignRight);
    
    293
    -  dpiSpinBox_->setRange(10, 600);
    
    294
    -  dpiLabel_->setBuddy(dpiSpinBox_);
    
    255
    +  sizeSelector_ = new FontSizeSelector(this);
    
    295 256
     
    
    296 257
       zoomLabel_ = new QLabel(tr("Zoom Factor"), this);
    
    297 258
       zoomLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    ... ... @@ -310,12 +271,7 @@ SingularTab::createLayout()
    310 271
     
    
    311 272
       sizeLayout_ = new QHBoxLayout;
    
    312 273
       sizeLayout_->addStretch(2);
    
    313
    -  sizeLayout_->addWidget(sizeLabel_);
    
    314
    -  sizeLayout_->addWidget(sizeDoubleSpinBox_);
    
    315
    -  sizeLayout_->addWidget(unitsComboBox_);
    
    316
    -  sizeLayout_->addStretch(1);
    
    317
    -  sizeLayout_->addWidget(dpiLabel_);
    
    318
    -  sizeLayout_->addWidget(dpiSpinBox_);
    
    274
    +  sizeLayout_->addWidget(sizeSelector_, 3);
    
    319 275
       sizeLayout_->addStretch(1);
    
    320 276
       sizeLayout_->addWidget(zoomLabel_);
    
    321 277
       sizeLayout_->addWidget(zoomSpinBox_);
    
    ... ... @@ -355,14 +311,10 @@ SingularTab::createLayout()
    355 311
     void
    
    356 312
     SingularTab::createConnections()
    
    357 313
     {
    
    314
    +  connect(sizeSelector_, &FontSizeSelector::valueChanged,
    
    315
    +          this, &SingularTab::repaintGlyph);
    
    358 316
       connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged, 
    
    359 317
               this, &SingularTab::setGlyphIndex);
    
    360
    -  connect(sizeDoubleSpinBox_, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    361
    -          this, &SingularTab::drawGlyph);
    
    362
    -  connect(unitsComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    363
    -          this, &SingularTab::checkUnits);
    
    364
    -  connect(dpiSpinBox_, QOverload<int>::of(&QSpinBox::valueChanged),
    
    365
    -          this, &SingularTab::drawGlyph);
    
    366 318
     
    
    367 319
       connect(zoomSpinBox_, QOverload<int>::of(&QSpinBox::valueChanged),
    
    368 320
               this, &SingularTab::zoom);
    
    ... ... @@ -389,36 +341,6 @@ SingularTab::createConnections()
    389 341
     }
    
    390 342
     
    
    391 343
     
    
    392
    -void
    
    393
    -SingularTab::setGraphicsDefaults()
    
    394
    -{
    
    395
    -  // color tables (with suitable opacity values) for converting
    
    396
    -  // FreeType's pixmaps to something Qt understands
    
    397
    -  monoColorTable_.append(QColor(Qt::transparent).rgba());
    
    398
    -  monoColorTable_.append(QColor(Qt::black).rgba());
    
    399
    -
    
    400
    -  for (int i = 0xFF; i >= 0; i--)
    
    401
    -    grayColorTable_.append(qRgba(i, i, i, 0xFF - i));
    
    402
    -
    
    403
    -  // XXX make this user-configurable
    
    404
    -
    
    405
    -  axisPen_.setColor(Qt::black);
    
    406
    -  axisPen_.setWidth(0);
    
    407
    -  blueZonePen_.setColor(QColor(64, 64, 255, 64)); // light blue
    
    408
    -  blueZonePen_.setWidth(0);
    
    409
    -  gridPen_.setColor(Qt::lightGray);
    
    410
    -  gridPen_.setWidth(0);
    
    411
    -  offPen_.setColor(Qt::darkGreen);
    
    412
    -  offPen_.setWidth(3);
    
    413
    -  onPen_.setColor(Qt::red);
    
    414
    -  onPen_.setWidth(3);
    
    415
    -  outlinePen_.setColor(Qt::red);
    
    416
    -  outlinePen_.setWidth(0);
    
    417
    -  segmentPen_.setColor(QColor(64, 255, 128, 64)); // light green
    
    418
    -  segmentPen_.setWidth(0);
    
    419
    -}
    
    420
    -
    
    421
    -
    
    422 344
     void
    
    423 345
     SingularTab::repaintGlyph()
    
    424 346
     {
    
    ... ... @@ -430,9 +352,7 @@ void
    430 352
     SingularTab::reloadFont()
    
    431 353
     {
    
    432 354
       currentGlyphCount_ = engine_->currentFontNumberOfGlyphs();
    
    433
    -  indexSelector_->setMin(0);
    
    434
    -  indexSelector_->setMax(currentGlyphCount_);
    
    435
    -  indexSelector_->setCurrentIndex(indexSelector_->getCurrentIndex(), true);
    
    355
    +  indexSelector_->setMinMax(0, currentGlyphCount_);
    
    436 356
       drawGlyph();
    
    437 357
     }
    
    438 358
     
    
    ... ... @@ -440,13 +360,7 @@ SingularTab::reloadFont()
    440 360
     void
    
    441 361
     SingularTab::syncSettings()
    
    442 362
     {
    
    443
    -  // Spinbox value cannot become negative
    
    444
    -  engine_->setDPI(static_cast<unsigned int>(dpiSpinBox_->value()));
    
    445
    -
    
    446
    -  if (unitsComboBox_->currentIndex() == Units_px)
    
    447
    -    engine_->setSizeByPixel(sizeDoubleSpinBox_->value());
    
    448
    -  else
    
    449
    -    engine_->setSizeByPoint(sizeDoubleSpinBox_->value());
    
    363
    +  sizeSelector_->applyToEngine(engine_);
    
    450 364
     }
    
    451 365
     
    
    452 366
     
    
    ... ... @@ -455,14 +369,11 @@ SingularTab::setDefaults()
    455 369
     {
    
    456 370
       currentGlyphIndex_ = 0;
    
    457 371
     
    
    458
    -  sizeDoubleSpinBox_->setValue(20);
    
    459
    -  dpiSpinBox_->setValue(96);
    
    460 372
       zoomSpinBox_->setValue(20);
    
    461 373
       showBitmapCheckBox_->setChecked(true);
    
    462 374
       showOutlinesCheckBox_->setChecked(true);
    
    463
    -
    
    464
    -  checkUnits();
    
    465
    -  indexSelector_->setCurrentIndex(indexSelector_->getCurrentIndex(), true);
    
    375
    +  
    
    376
    +  indexSelector_->setCurrentIndex(indexSelector_->currentIndex(), true);
    
    466 377
       zoom();
    
    467 378
     }
    
    468 379
     
    

  • src/ftinspect/panels/singular.hpp
    ... ... @@ -7,11 +7,13 @@
    7 7
     #include "abstracttab.hpp"
    
    8 8
     #include "../widgets/customwidgets.hpp"
    
    9 9
     #include "../widgets/glyphindexselector.hpp"
    
    10
    +#include "../widgets/fontsizeselector.hpp"
    
    10 11
     #include "../rendering/glyphbitmap.hpp"
    
    11 12
     #include "../rendering/glyphoutline.hpp"
    
    12 13
     #include "../rendering/glyphpointnumbers.hpp"
    
    13 14
     #include "../rendering/glyphpoints.hpp"
    
    14 15
     #include "../rendering/grid.hpp"
    
    16
    +#include "../rendering/graphicsdefault.hpp"
    
    15 17
     #include "../engine/engine.hpp"
    
    16 18
     #include "../models/ttsettingscomboboxmodel.hpp"
    
    17 19
     
    
    ... ... @@ -45,8 +47,7 @@ public:
    45 47
     private slots:
    
    46 48
       void setGlyphIndex(int);
    
    47 49
       void drawGlyph();
    
    48
    -
    
    49
    -  void checkUnits();
    
    50
    +  
    
    50 51
       void checkShowPoints();
    
    51 52
     
    
    52 53
       void zoom();
    
    ... ... @@ -71,13 +72,9 @@ private:
    71 72
       QLabel* mouseUsageHint_;
    
    72 73
     
    
    73 74
       GlyphIndexSelector* indexSelector_;
    
    74
    -  QLabel* dpiLabel_;
    
    75
    -  QLabel* sizeLabel_;
    
    75
    +  FontSizeSelector* sizeSelector_;
    
    76 76
       QLabel* zoomLabel_;
    
    77
    -  QSpinBox* dpiSpinBox_;
    
    78 77
       ZoomSpinBox* zoomSpinBox_;
    
    79
    -  QComboBox* unitsComboBox_;
    
    80
    -  QDoubleSpinBox* sizeDoubleSpinBox_;
    
    81 78
       QPushButton* centerGridButton_;
    
    82 79
     
    
    83 80
       QLabel* glyphIndexLabel_;
    
    ... ... @@ -94,26 +91,10 @@ private:
    94 91
       QGridLayout* glyphOverlayLayout_;
    
    95 92
       QHBoxLayout* glyphOverlayIndexLayout_;
    
    96 93
     
    
    97
    -  QPen axisPen_;
    
    98
    -  QPen blueZonePen_;
    
    99
    -  QPen gridPen_;
    
    100
    -  QPen offPen_;
    
    101
    -  QPen onPen_;
    
    102
    -  QPen outlinePen_;
    
    103
    -  QPen segmentPen_;
    
    104
    -
    
    105
    -  QVector<QRgb> grayColorTable_;
    
    106
    -  QVector<QRgb> monoColorTable_;
    
    107
    -
    
    108
    -  enum Units
    
    109
    -  {
    
    110
    -    Units_px,
    
    111
    -    Units_pt
    
    112
    -  };
    
    94
    +  GraphicsDefault* graphicsDefault_;
    
    113 95
     
    
    114 96
       void createLayout();
    
    115 97
       void createConnections();
    
    116
    -  void setGraphicsDefaults();
    
    117 98
       
    
    118 99
       void updateGrid();
    
    119 100
     };
    

  • src/ftinspect/rendering/glyphbitmap.cpp
    ... ... @@ -5,6 +5,8 @@
    5 5
     
    
    6 6
     #include "glyphbitmap.hpp"
    
    7 7
     
    
    8
    +#include "renderutils.hpp"
    
    9
    +
    
    8 10
     #include <cmath>
    
    9 11
     #include <QPainter>
    
    10 12
     #include <QStyleOptionGraphicsItem>
    
    ... ... @@ -21,23 +23,8 @@ GlyphBitmap::GlyphBitmap(FT_Outline* outline,
    21 23
       grayColorTable_(grayColorTbl)
    
    22 24
     {
    
    23 25
       // 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 26
       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
    -
    
    27
    +  transformed_ = transformOutlineToOrigin(lib, outline, &cbox);
    
    41 28
       boundingRect_.setCoords(cbox.xMin / 64, -cbox.yMax / 64,
    
    42 29
                       cbox.xMax / 64, -cbox.yMin / 64);
    
    43 30
     }
    

  • src/ftinspect/rendering/glyphcontinuous.cpp
    1
    +// glyphcontinuous.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "glyphcontinuous.hpp"
    
    6
    +
    
    7
    +#include <cmath>
    
    8
    +#include <QPainter>
    
    9
    +#include <QWheelEvent>
    
    10
    +
    
    11
    +#include "../engine/engine.hpp"
    
    12
    +#include "../rendering/renderutils.hpp"
    
    13
    +
    
    14
    +
    
    15
    +GlyphContinuous::GlyphContinuous(QWidget* parent, Engine* engine)
    
    16
    +: QWidget(parent), engine_(engine)
    
    17
    +{
    
    18
    +  setAcceptDrops(false);
    
    19
    +  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
    20
    +  graphicsDefault_ = GraphicsDefault::deafultInstance();
    
    21
    +}
    
    22
    +
    
    23
    +
    
    24
    +void
    
    25
    +GlyphContinuous::paintEvent(QPaintEvent* event)
    
    26
    +{
    
    27
    +  QPainter painter;
    
    28
    +  painter.begin(this);
    
    29
    +  painter.fillRect(rect(), Qt::white);
    
    30
    +
    
    31
    +  if (limitIndex_ > 0)
    
    32
    +  {
    
    33
    +    prePaint();
    
    34
    +
    
    35
    +    switch (mode_)
    
    36
    +    {
    
    37
    +    case AllGlyphs:
    
    38
    +      switch (modeAG_)
    
    39
    +      {
    
    40
    +      case AG_AllGlyphs:
    
    41
    +        paintAGAllGlyphs(&painter);
    
    42
    +        break;
    
    43
    +        // TODO more modes
    
    44
    +      case AG_Fancy:
    
    45
    +        break;
    
    46
    +      case AG_Stroked:
    
    47
    +        break;
    
    48
    +      case AG_Waterfall:
    
    49
    +        break;
    
    50
    +      }
    
    51
    +      break;
    
    52
    +    case TextString:
    
    53
    +      break;
    
    54
    +    }
    
    55
    +    emit displayingCountUpdated(displayingCount_);
    
    56
    +  }
    
    57
    +
    
    58
    +  painter.end();
    
    59
    +}
    
    60
    +
    
    61
    +
    
    62
    +void
    
    63
    +GlyphContinuous::wheelEvent(QWheelEvent* event)
    
    64
    +{
    
    65
    +  int numSteps = event->angleDelta().y() / 120;
    
    66
    +  if (event->modifiers() & Qt::ShiftModifier)
    
    67
    +    emit wheelResize(numSteps);
    
    68
    +  else if (event->modifiers() == 0)
    
    69
    +    emit wheelNavigate(-numSteps);
    
    70
    +}
    
    71
    +
    
    72
    +
    
    73
    +void
    
    74
    +GlyphContinuous::paintAGAllGlyphs(QPainter* painter)
    
    75
    +{
    
    76
    +  for (int i = beginIndex_; i < limitIndex_; i++)
    
    77
    +  {
    
    78
    +    unsigned index = i;
    
    79
    +    if (charMapIndex_ >= 0)
    
    80
    +      index = engine_->glyphIndexFromCharCode(i, charMapIndex_);
    
    81
    +
    
    82
    +    if (!paintChar(painter, index))
    
    83
    +      break;
    
    84
    +
    
    85
    +    displayingCount_++;
    
    86
    +  }
    
    87
    +}
    
    88
    +
    
    89
    +
    
    90
    +void
    
    91
    +GlyphContinuous::prePaint()
    
    92
    +{
    
    93
    +  displayingCount_ = 0;
    
    94
    +  engine_->reloadFont();
    
    95
    +  metrics_ = engine_->currentFontMetrics();
    
    96
    +  x_ = 0;
    
    97
    +  // See ftview.c:42
    
    98
    +  y_ = ((metrics_.ascender - metrics_.descender + 63) >> 6) + 4;
    
    99
    +  stepY_ = ((metrics_.height + 63) >> 6) + 4;
    
    100
    +}
    
    101
    +
    
    102
    +
    
    103
    +bool
    
    104
    +GlyphContinuous::paintChar(QPainter* painter,
    
    105
    +                           int index)
    
    106
    +{
    
    107
    +  auto glyph = engine_->loadGlyphWithoutUpdate(index);
    
    108
    +  if (!glyph)
    
    109
    +    return false;
    
    110
    +
    
    111
    +  // ftview.c:557
    
    112
    +  int width = glyph->advance.x ? glyph->advance.x >> 16
    
    113
    +                               : metrics_.y_ppem / 2;
    
    114
    +
    
    115
    +  if (!checkFitX(x_ + width))
    
    116
    +  {
    
    117
    +    x_ = 0;
    
    118
    +    y_ += stepY_;
    
    119
    +
    
    120
    +    if (!checkFitY(y_))
    
    121
    +      return false;
    
    122
    +  }
    
    123
    +
    
    124
    +  x_++; // extra space
    
    125
    +  if (glyph->advance.x == 0)
    
    126
    +  {
    
    127
    +    // Draw a red square to indicate
    
    128
    +      painter->fillRect(x_, y_ - width, width, width,
    
    129
    +                        Qt::red);
    
    130
    +    x_ += width;
    
    131
    +  }
    
    132
    +
    
    133
    +  // The real drawing part
    
    134
    +  // XXX: this is different from what's being done in
    
    135
    +  // `ftcommon.c`:FTDemo_Draw_Slot: is this correct??
    
    136
    +
    
    137
    +  // First translate the outline
    
    138
    +
    
    139
    +  if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
    
    140
    +    return true; // XXX only outline is supported - need to impl others later
    
    141
    +
    
    142
    +  FT_BBox cbox;
    
    143
    +  // Don't forget to free this when returning
    
    144
    +  auto outline = transformOutlineToOrigin(
    
    145
    +                   engine_->ftLibrary(),
    
    146
    +                   &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline,
    
    147
    +                   &cbox);
    
    148
    +  
    
    149
    +  auto outlineWidth = (cbox.xMax - cbox.xMin) / 64;
    
    150
    +  auto outlineHeight = (cbox.yMax - cbox.yMin) / 64;
    
    151
    +
    
    152
    +  // Then convert to bitmap
    
    153
    +  FT_Bitmap bitmap;
    
    154
    +  QImage::Format format = QImage::Format_Indexed8;
    
    155
    +  auto aaEnabled = engine_->antiAliasingEnabled();
    
    156
    +
    
    157
    +  // TODO cover LCD and color
    
    158
    +  if (!aaEnabled)
    
    159
    +    format = QImage::Format_Mono;
    
    160
    +
    
    161
    +  // TODO optimization: reuse QImage?
    
    162
    +  QImage image(QSize(outlineWidth, outlineHeight), format);
    
    163
    +
    
    164
    +  if (!aaEnabled)
    
    165
    +    image.setColorTable(graphicsDefault_->monoColorTable);
    
    166
    +  else
    
    167
    +    image.setColorTable(graphicsDefault_->grayColorTable);
    
    168
    +
    
    169
    +  image.fill(0);
    
    170
    +
    
    171
    +  bitmap.rows = static_cast<unsigned int>(outlineHeight);
    
    172
    +  bitmap.width = static_cast<unsigned int>(outlineWidth);
    
    173
    +  bitmap.buffer = image.bits();
    
    174
    +  bitmap.pitch = image.bytesPerLine();
    
    175
    +  bitmap.pixel_mode = aaEnabled ? FT_PIXEL_MODE_GRAY : FT_PIXEL_MODE_MONO;
    
    176
    +
    
    177
    +  FT_Error error = FT_Outline_Get_Bitmap(engine_->ftLibrary(),
    
    178
    +                                         &outline,
    
    179
    +                                         &bitmap);
    
    180
    +  if (error)
    
    181
    +  {
    
    182
    +    // XXX error handling
    
    183
    +    FT_Outline_Done(engine_->ftLibrary(), &outline);
    
    184
    +    return true;
    
    185
    +  }
    
    186
    +
    
    187
    +  painter->drawImage(
    
    188
    +      QPoint(x_ + cbox.xMin / 64, y_ + (-cbox.yMax / 64)),
    
    189
    +      image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
    
    190
    +
    
    191
    +  x_ += width;
    
    192
    +
    
    193
    +  FT_Outline_Done(engine_->ftLibrary(), &outline);
    
    194
    +  return true;
    
    195
    +}
    
    196
    +
    
    197
    +
    
    198
    +bool
    
    199
    +GlyphContinuous::checkFitX(int x)
    
    200
    +{
    
    201
    +  return x < width() - 3;
    
    202
    +}
    
    203
    +
    
    204
    +
    
    205
    +bool
    
    206
    +GlyphContinuous::checkFitY(int y)
    
    207
    +{
    
    208
    +  return y < height() - 3;
    
    209
    +}
    
    210
    +
    
    211
    +
    
    212
    +// end of glyphcontinuous.cpp

  • src/ftinspect/rendering/glyphcontinuous.hpp
    1
    +// glyphcontinuous.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include "graphicsdefault.hpp"
    
    8
    +#include <QWidget>
    
    9
    +#include <freetype/freetype.h>
    
    10
    +
    
    11
    +class Engine;
    
    12
    +class GlyphContinuous
    
    13
    +: public QWidget
    
    14
    +{
    
    15
    +  Q_OBJECT
    
    16
    +public:
    
    17
    +  GlyphContinuous(QWidget* parent, Engine* engine);
    
    18
    +  ~GlyphContinuous() override = default;
    
    19
    +
    
    20
    +  enum Mode : int
    
    21
    +  {
    
    22
    +    AllGlyphs,
    
    23
    +    TextString
    
    24
    +  };
    
    25
    +
    
    26
    +  enum SubModeAllGlyphs : int
    
    27
    +  {
    
    28
    +    AG_AllGlyphs,
    
    29
    +    AG_Fancy,
    
    30
    +    AG_Stroked,
    
    31
    +    AG_Waterfall
    
    32
    +  };
    
    33
    +
    
    34
    +  int displayingCount() { return displayingCount_; }
    
    35
    +
    
    36
    +  // all those setters don't trigger repaint.
    
    37
    +  void setBeginIndex(int index) { beginIndex_ = index; }
    
    38
    +  void setLimitIndex(int index) { limitIndex_ = index; }
    
    39
    +  void setCharMapIndex(int index) { charMapIndex_ = index; }
    
    40
    +  void setMode(Mode mode) { mode_ = mode; }
    
    41
    +  void setSubModeAllGlyphs(SubModeAllGlyphs modeAg) { modeAG_ = modeAg; }
    
    42
    +
    
    43
    +signals:
    
    44
    +  void wheelNavigate(int steps);
    
    45
    +  void wheelResize(int steps);
    
    46
    +  void displayingCountUpdated(int newCount);
    
    47
    +
    
    48
    +protected:
    
    49
    +  void paintEvent(QPaintEvent* event) override;
    
    50
    +  void wheelEvent(QWheelEvent* event) override;
    
    51
    +
    
    52
    +private:
    
    53
    +  Engine* engine_;
    
    54
    +  GraphicsDefault* graphicsDefault_;
    
    55
    +
    
    56
    +  int beginIndex_;
    
    57
    +  int limitIndex_;
    
    58
    +  int charMapIndex_;
    
    59
    +  Mode mode_ = AllGlyphs;
    
    60
    +  SubModeAllGlyphs modeAG_ = AG_AllGlyphs;
    
    61
    +
    
    62
    +  int displayingCount_ = 0;
    
    63
    +  FT_Size_Metrics metrics_;
    
    64
    +  int x_ = 0, y_ = 0;
    
    65
    +  int stepY_ = 0;
    
    66
    +
    
    67
    +  void paintAGAllGlyphs(QPainter* painter);
    
    68
    +  void prePaint();
    
    69
    +  // return if there's enough space to paint the current char
    
    70
    +  bool paintChar(QPainter* painter, int index);
    
    71
    +
    
    72
    +  bool checkFitX(int x);
    
    73
    +  bool checkFitY(int y);
    
    74
    +};
    
    75
    +
    
    76
    +
    
    77
    +// end of glyphcontinuous.hpp

  • src/ftinspect/rendering/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
    +  // color tables (with suitable opacity values) for converting
    
    12
    +  // FreeType's pixmaps to something Qt understands
    
    13
    +  monoColorTable.append(QColor(Qt::transparent).rgba());
    
    14
    +  monoColorTable.append(QColor(Qt::black).rgba());
    
    15
    +
    
    16
    +  for (int i = 0xFF; i >= 0; i--)
    
    17
    +    grayColorTable.append(qRgba(i, i, i, 0xFF - i));
    
    18
    +
    
    19
    +  // XXX make this user-configurable
    
    20
    +
    
    21
    +  axisPen.setColor(Qt::black);
    
    22
    +  axisPen.setWidth(0);
    
    23
    +  blueZonePen.setColor(QColor(64, 64, 255, 64)); // light blue
    
    24
    +  blueZonePen.setWidth(0);
    
    25
    +  gridPen.setColor(Qt::lightGray);
    
    26
    +  gridPen.setWidth(0);
    
    27
    +  offPen.setColor(Qt::darkGreen);
    
    28
    +  offPen.setWidth(3);
    
    29
    +  onPen.setColor(Qt::red);
    
    30
    +  onPen.setWidth(3);
    
    31
    +  outlinePen.setColor(Qt::red);
    
    32
    +  outlinePen.setWidth(0);
    
    33
    +  segmentPen.setColor(QColor(64, 255, 128, 64)); // light green
    
    34
    +  segmentPen.setWidth(0);
    
    35
    +}
    
    36
    +
    
    37
    +
    
    38
    +GraphicsDefault*
    
    39
    +GraphicsDefault::deafultInstance()
    
    40
    +{
    
    41
    +  if (!instance_)
    
    42
    +    instance_ = new GraphicsDefault;
    
    43
    +
    
    44
    +  return instance_;
    
    45
    +}
    
    46
    +
    
    47
    +
    
    48
    +// end of graphicsdefault.cpp

  • src/ftinspect/rendering/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
    +  QVector<QRgb> grayColorTable;
    
    15
    +  QVector<QRgb> monoColorTable;
    
    16
    +
    
    17
    +  QPen axisPen;
    
    18
    +  QPen blueZonePen;
    
    19
    +  QPen gridPen;
    
    20
    +  QPen offPen;
    
    21
    +  QPen onPen;
    
    22
    +  QPen outlinePen;
    
    23
    +  QPen segmentPen;
    
    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/rendering/renderutils.cpp
    1
    +// renderutils.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "renderutils.hpp"
    
    6
    +
    
    7
    +FT_Outline
    
    8
    +transformOutlineToOrigin(FT_Library library, 
    
    9
    +                         FT_Outline* outline,
    
    10
    +                         FT_BBox* outControlBox)
    
    11
    +{
    
    12
    +  FT_Outline transformed;
    
    13
    +  FT_Outline_New(library,
    
    14
    +                 static_cast<unsigned int>(outline->n_points),
    
    15
    +                 outline->n_contours, &transformed);
    
    16
    +  FT_Outline_Copy(outline, &transformed);
    
    17
    +
    
    18
    +  FT_BBox cbox;
    
    19
    +  FT_Outline_Get_CBox(outline, &cbox);
    
    20
    +
    
    21
    +  cbox.xMin &= ~63;
    
    22
    +  cbox.yMin &= ~63;
    
    23
    +  cbox.xMax = (cbox.xMax + 63) & ~63;
    
    24
    +  cbox.yMax = (cbox.yMax + 63) & ~63;
    
    25
    +  // we shift the outline to the origin for rendering later on
    
    26
    +  FT_Outline_Translate(&transformed, -cbox.xMin, -cbox.yMin);
    
    27
    +
    
    28
    +  if (outControlBox)
    
    29
    +    *outControlBox = cbox;
    
    30
    +  return transformed;
    
    31
    +}
    
    32
    +
    
    33
    +
    
    34
    +// end of renderutils.cpp

  • src/ftinspect/rendering/renderutils.hpp
    1
    +// renderutils.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include <freetype/ftoutln.h>
    
    8
    +
    
    9
    +// The constructed `outline` must be freed by the caller
    
    10
    +FT_Outline transformOutlineToOrigin(FT_Library library, 
    
    11
    +                                    FT_Outline* outline,
    
    12
    +                                    FT_BBox* outControlBox);
    
    13
    +
    
    14
    +
    
    15
    +// end of renderutils.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
    +FontSizeSelector::FontSizeSelector(QWidget* parent)
    
    10
    +: QWidget(parent)
    
    11
    +{
    
    12
    +  createLayout();
    
    13
    +  createConnections();
    
    14
    +  setDefaults();
    
    15
    +}
    
    16
    +
    
    17
    +
    
    18
    +double
    
    19
    +FontSizeSelector::selectedSize()
    
    20
    +{
    
    21
    +  return sizeDoubleSpinBox_->value();
    
    22
    +}
    
    23
    +
    
    24
    +
    
    25
    +FontSizeSelector::Units
    
    26
    +FontSizeSelector::selectedUnit()
    
    27
    +{
    
    28
    +  return static_cast<Units>(unitsComboBox_->currentIndex());
    
    29
    +}
    
    30
    +
    
    31
    +
    
    32
    +void
    
    33
    +FontSizeSelector::applyToEngine(Engine* engine)
    
    34
    +{
    
    35
    +  // Spinbox value cannot become negative
    
    36
    +  engine->setDPI(dpiSpinBox_->value());
    
    37
    +
    
    38
    +  if (unitsComboBox_->currentIndex() == Units_px)
    
    39
    +    engine->setSizeByPixel(sizeDoubleSpinBox_->value());
    
    40
    +  else
    
    41
    +    engine->setSizeByPoint(sizeDoubleSpinBox_->value());
    
    42
    +}
    
    43
    +
    
    44
    +
    
    45
    +void
    
    46
    +FontSizeSelector::handleWheelResizeBySteps(int steps)
    
    47
    +{
    
    48
    +  double sizeAfter = sizeDoubleSpinBox_->value() + steps * 0.5;
    
    49
    +  sizeAfter = std::max(sizeDoubleSpinBox_->minimum(),
    
    50
    +                       std::min(sizeAfter, sizeDoubleSpinBox_->maximum()));
    
    51
    +  sizeDoubleSpinBox_->setValue(sizeAfter);
    
    52
    +}
    
    53
    +
    
    54
    +
    
    55
    +void
    
    56
    +FontSizeSelector::handleWheelResizeFromGrid(QWheelEvent* event)
    
    57
    +{
    
    58
    +  int numSteps = event->angleDelta().y() / 120;
    
    59
    +  handleWheelResizeBySteps(numSteps);
    
    60
    +}
    
    61
    +
    
    62
    +
    
    63
    +void
    
    64
    +FontSizeSelector::checkUnits()
    
    65
    +{
    
    66
    +  int index = unitsComboBox_->currentIndex();
    
    67
    +
    
    68
    +  if (index == Units_px)
    
    69
    +  {
    
    70
    +    dpiLabel_->setEnabled(false);
    
    71
    +    dpiSpinBox_->setEnabled(false);
    
    72
    +    sizeDoubleSpinBox_->setSingleStep(1);
    
    73
    +
    
    74
    +    QSignalBlocker blocker(sizeDoubleSpinBox_);
    
    75
    +    sizeDoubleSpinBox_->setValue(qRound(sizeDoubleSpinBox_->value()));
    
    76
    +  }
    
    77
    +  else
    
    78
    +  {
    
    79
    +    dpiLabel_->setEnabled(true);
    
    80
    +    dpiSpinBox_->setEnabled(true);
    
    81
    +    sizeDoubleSpinBox_->setSingleStep(0.5);
    
    82
    +  }
    
    83
    +
    
    84
    +  emit valueChanged();
    
    85
    +}
    
    86
    +
    
    87
    +
    
    88
    +void
    
    89
    +FontSizeSelector::createLayout()
    
    90
    +{
    
    91
    +  sizeLabel_ = new QLabel(tr("Size "), this);
    
    92
    +  sizeLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    93
    +  sizeDoubleSpinBox_ = new QDoubleSpinBox;
    
    94
    +  sizeDoubleSpinBox_->setAlignment(Qt::AlignRight);
    
    95
    +  sizeDoubleSpinBox_->setDecimals(1);
    
    96
    +  sizeDoubleSpinBox_->setRange(1, 500);
    
    97
    +  sizeLabel_->setBuddy(sizeDoubleSpinBox_);
    
    98
    +
    
    99
    +  unitsComboBox_ = new QComboBox(this);
    
    100
    +  unitsComboBox_->insertItem(Units_px, "px");
    
    101
    +  unitsComboBox_->insertItem(Units_pt, "pt");
    
    102
    +
    
    103
    +  dpiLabel_ = new QLabel(tr("DPI "), this);
    
    104
    +  dpiLabel_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    
    105
    +  dpiSpinBox_ = new QSpinBox(this);
    
    106
    +  dpiSpinBox_->setAlignment(Qt::AlignRight);
    
    107
    +  dpiSpinBox_->setRange(10, 600);
    
    108
    +  dpiLabel_->setBuddy(dpiSpinBox_);
    
    109
    +
    
    110
    +  layout_ = new QHBoxLayout;
    
    111
    +
    
    112
    +  layout_->addStretch(1);
    
    113
    +  layout_->addWidget(sizeLabel_);
    
    114
    +  layout_->addWidget(sizeDoubleSpinBox_);
    
    115
    +  layout_->addWidget(unitsComboBox_);
    
    116
    +  layout_->addStretch(1);
    
    117
    +  layout_->addWidget(dpiLabel_);
    
    118
    +  layout_->addWidget(dpiSpinBox_);
    
    119
    +  layout_->addStretch(1);
    
    120
    +
    
    121
    +  setLayout(layout_);
    
    122
    +  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    123
    +}
    
    124
    +
    
    125
    +
    
    126
    +void
    
    127
    +FontSizeSelector::createConnections()
    
    128
    +{
    
    129
    +  connect(sizeDoubleSpinBox_, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
    
    130
    +          this, &FontSizeSelector::valueChanged);
    
    131
    +  connect(unitsComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    132
    +          this, &FontSizeSelector::checkUnits);
    
    133
    +  connect(dpiSpinBox_, QOverload<int>::of(&QSpinBox::valueChanged),
    
    134
    +          this, &FontSizeSelector::valueChanged);
    
    135
    +}
    
    136
    +
    
    137
    +
    
    138
    +void
    
    139
    +FontSizeSelector::setDefaults()
    
    140
    +{
    
    141
    +  sizeDoubleSpinBox_->setValue(20);
    
    142
    +  dpiSpinBox_->setValue(96);
    
    143
    +  checkUnits();
    
    144
    +}
    
    145
    +
    
    146
    +
    
    147
    +// 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 <QComboBox>
    
    8
    +#include <QDoubleSpinBox>
    
    9
    +#include <QLabel>
    
    10
    +#include <QWidget>
    
    11
    +#include <QBoxLayout>
    
    12
    +#include <QWheelEvent>
    
    13
    +
    
    14
    +class Engine;
    
    15
    +class FontSizeSelector : public QWidget
    
    16
    +{
    
    17
    +  Q_OBJECT
    
    18
    +
    
    19
    +public:
    
    20
    +  FontSizeSelector(QWidget* parent);
    
    21
    +  ~FontSizeSelector() override = default;
    
    22
    +
    
    23
    +  enum Units : int
    
    24
    +  {
    
    25
    +    Units_px,
    
    26
    +    Units_pt
    
    27
    +  };
    
    28
    +
    
    29
    +  double selectedSize();
    
    30
    +  Units selectedUnit();
    
    31
    +
    
    32
    +  void applyToEngine(Engine* engine);
    
    33
    +  void handleWheelResizeBySteps(int steps);
    
    34
    +  void handleWheelResizeFromGrid(QWheelEvent* event);
    
    35
    +
    
    36
    +signals:
    
    37
    +  void valueChanged();
    
    38
    +
    
    39
    +private slots:
    
    40
    +  void checkUnits();
    
    41
    +
    
    42
    +private:
    
    43
    +  QLabel* sizeLabel_;
    
    44
    +  QLabel* dpiLabel_;
    
    45
    +
    
    46
    +  QDoubleSpinBox* sizeDoubleSpinBox_;
    
    47
    +  QComboBox* unitsComboBox_;
    
    48
    +  QSpinBox* dpiSpinBox_;
    
    49
    +
    
    50
    +  QHBoxLayout* layout_;
    
    51
    +
    
    52
    +  void createLayout();
    
    53
    +  void createConnections();
    
    54
    +  void setDefaults();
    
    55
    +};
    
    56
    +
    
    57
    +
    
    58
    +// end of fontsizeselector.hpp

  • src/ftinspect/widgets/glyphindexselector.cpp
    ... ... @@ -6,33 +6,33 @@
    6 6
     
    
    7 7
     #include "../uihelper.hpp"
    
    8 8
     
    
    9
    +#include <climits>
    
    10
    +
    
    9 11
     GlyphIndexSelector::GlyphIndexSelector(QWidget* parent)
    
    10 12
     : QWidget(parent)
    
    11 13
     {
    
    14
    +  numberRenderer_ = &GlyphIndexSelector::renderNumberDefault;
    
    15
    +
    
    12 16
       createLayout();
    
    13 17
       createConnections();
    
    18
    +  showingCount_ = 0;
    
    14 19
     }
    
    15 20
     
    
    16 21
     
    
    17 22
     void
    
    18
    -GlyphIndexSelector::setMin(int min)
    
    23
    +GlyphIndexSelector::setMinMax(int min,
    
    24
    +                              int max)
    
    19 25
     {
    
    26
    +  // Don't emit events during setting
    
    27
    +  auto eventState = blockSignals(true);
    
    20 28
       indexSpinBox_->setMinimum(min);
    
    29
    +  indexSpinBox_->setMaximum(qBound(0, max, INT_MAX));
    
    21 30
       indexSpinBox_->setValue(qBound(indexSpinBox_->minimum(),
    
    22 31
                                      indexSpinBox_->value(),
    
    23 32
                                      indexSpinBox_->maximum()));
    
    24
    -  // spinBoxChanged will be automatically called
    
    25
    -}
    
    33
    +  blockSignals(eventState);
    
    26 34
     
    
    27
    -
    
    28
    -void
    
    29
    -GlyphIndexSelector::setMax(int max)
    
    30
    -{
    
    31
    -  indexSpinBox_->setMaximum(max);
    
    32
    -  indexSpinBox_->setValue(qBound(indexSpinBox_->minimum(),
    
    33
    -                                 indexSpinBox_->value(),
    
    34
    -                                 indexSpinBox_->maximum()));
    
    35
    -  // spinBoxChanged will be automatically called
    
    35
    +  updateLabel();
    
    36 36
     }
    
    37 37
     
    
    38 38
     
    
    ... ... @@ -55,26 +55,41 @@ GlyphIndexSelector::setSingleMode(bool singleMode)
    55 55
     void
    
    56 56
     GlyphIndexSelector::setCurrentIndex(int index, bool forceUpdate)
    
    57 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);
    
    58 62
       indexSpinBox_->setValue(index);
    
    59
    -  updateLabel();
    
    63
    +  blockSignals(state);
    
    64
    +  
    
    60 65
       if (forceUpdate)
    
    61 66
         emit currentIndexChanged(indexSpinBox_->value());
    
    62 67
     }
    
    63 68
     
    
    64 69
     
    
    65 70
     int
    
    66
    -GlyphIndexSelector::getCurrentIndex()
    
    71
    +GlyphIndexSelector::currentIndex()
    
    67 72
     {
    
    68 73
       return indexSpinBox_->value();
    
    69 74
     }
    
    70 75
     
    
    71 76
     
    
    77
    +void
    
    78
    +GlyphIndexSelector::setNumberRenderer(std::function<QString(int)> renderer)
    
    79
    +{
    
    80
    +  numberRenderer_ = std::move(renderer);
    
    81
    +}
    
    82
    +
    
    83
    +
    
    72 84
     void
    
    73 85
     GlyphIndexSelector::adjustIndex(int delta)
    
    74 86
     {
    
    75
    -  indexSpinBox_->setValue(qBound(indexSpinBox_->minimum(),
    
    76
    -                                 indexSpinBox_->value() + delta,
    
    77
    -                                 indexSpinBox_->maximum()));
    
    87
    +  {
    
    88
    +    QSignalBlocker blocker(this);
    
    89
    +    indexSpinBox_->setValue(qBound(indexSpinBox_->minimum(),
    
    90
    +                                   indexSpinBox_->value() + delta,
    
    91
    +                                   indexSpinBox_->maximum()));
    
    92
    +  }
    
    78 93
       emitValueChanged();
    
    79 94
     }
    
    80 95
     
    
    ... ... @@ -92,13 +107,17 @@ GlyphIndexSelector::updateLabel()
    92 107
     {
    
    93 108
       if (singleMode_)
    
    94 109
         indexLabel_->setText(QString("%1\nLimit: %2")
    
    95
    -                             .arg(indexSpinBox_->value())
    
    96
    -                             .arg(indexSpinBox_->maximum()));
    
    110
    +                           .arg(numberRenderer_(indexSpinBox_->value()))
    
    111
    +                           .arg(numberRenderer_(indexSpinBox_->maximum())));
    
    97 112
       else
    
    98
    -    indexLabel_->setText(QString("%1~%2\nCount: %3\nLimit: %4")
    
    99
    -                             .arg(indexSpinBox_->value())
    
    100
    -                             .arg(indexSpinBox_->value() + showingCount_ - 1)
    
    101
    -                             .arg(showingCount_, indexSpinBox_->maximum()));
    
    113
    +    indexLabel_->setText(
    
    114
    +      QString("%1~%2\nCount: %3\nLimit: %4")
    
    115
    +        .arg(numberRenderer_(indexSpinBox_->value()))
    
    116
    +        .arg(numberRenderer_(
    
    117
    +          qBound(indexSpinBox_->value(),
    
    118
    +                 indexSpinBox_->value() + showingCount_ - 1, INT_MAX)))
    
    119
    +        .arg(showingCount_)
    
    120
    +        .arg(numberRenderer_(indexSpinBox_->maximum())));
    
    102 121
     }
    
    103 122
     
    
    104 123
     
    
    ... ... @@ -121,9 +140,10 @@ GlyphIndexSelector::createLayout()
    121 140
       indexSpinBox_->setButtonSymbols(QAbstractSpinBox::NoButtons);
    
    122 141
       indexSpinBox_->setRange(0, 0);
    
    123 142
       indexSpinBox_->setFixedWidth(80);
    
    124
    -  indexSpinBox_->setWrapping(true);
    
    143
    +  indexSpinBox_->setWrapping(false);
    
    125 144
     
    
    126 145
       indexLabel_ = new QLabel("0\nCount: 0\nLimit: 0");
    
    146
    +  indexLabel_->setMinimumWidth(200);
    
    127 147
     
    
    128 148
       setButtonNarrowest(toStartButton_);
    
    129 149
       setButtonNarrowest(toM1000Button_);
    
    ... ... @@ -155,6 +175,7 @@ GlyphIndexSelector::createLayout()
    155 175
       navigationLayout_->addWidget(indexLabel_);
    
    156 176
       navigationLayout_->addStretch(3);
    
    157 177
     
    
    178
    +  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    158 179
       setLayout(navigationLayout_);
    
    159 180
     }
    
    160 181
     
    
    ... ... @@ -201,4 +222,11 @@ GlyphIndexSelector::createConnections()
    201 222
     }
    
    202 223
     
    
    203 224
     
    
    225
    +QString
    
    226
    +GlyphIndexSelector::renderNumberDefault(int i)
    
    227
    +{
    
    228
    +  return QString::number(i);
    
    229
    +}
    
    230
    +
    
    231
    +
    
    204 232
     // end of glyphindexselector.cpp

  • src/ftinspect/widgets/glyphindexselector.hpp
    ... ... @@ -4,6 +4,7 @@
    4 4
     
    
    5 5
     #pragma once
    
    6 6
     
    
    7
    +#include <functional>
    
    7 8
     #include <QWidget>
    
    8 9
     #include <QPushButton>
    
    9 10
     #include <QSpinBox>
    
    ... ... @@ -19,13 +20,15 @@ public:
    19 20
       GlyphIndexSelector(QWidget* parent);
    
    20 21
       ~GlyphIndexSelector() override = default;
    
    21 22
     
    
    22
    -  void setMin(int min);
    
    23
    -  void setMax(int max);
    
    23
    +  // Will never trigger repaint!
    
    24
    +  void setMinMax(int min, int max);
    
    24 25
       void setShowingCount(int showingCount);
    
    25 26
       void setSingleMode(bool singleMode);
    
    26 27
     
    
    27 28
       void setCurrentIndex(int index, bool forceUpdate = false);
    
    28
    -  int getCurrentIndex();
    
    29
    +  int currentIndex();
    
    30
    +
    
    31
    +  void setNumberRenderer(std::function<QString(int)> renderer);
    
    29 32
     
    
    30 33
     signals:
    
    31 34
       void currentIndexChanged(int index);
    
    ... ... @@ -38,6 +41,7 @@ private slots:
    38 41
     private:
    
    39 42
       bool singleMode_ = true;
    
    40 43
       int showingCount_;
    
    44
    +  std::function<QString(int)> numberRenderer_;
    
    41 45
     
    
    42 46
       // min, max and current status are held by `indexSpinBox_`
    
    43 47
     
    
    ... ... @@ -61,6 +65,8 @@ private:
    61 65
     
    
    62 66
       void createLayout();
    
    63 67
       void createConnections();
    
    68
    +
    
    69
    +  static QString renderNumberDefault(int i);
    
    64 70
     };
    
    65 71
     
    
    66 72
     
    


  • reply via email to

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