freetype-commit
[Top][All Lists]
Advanced

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

[freetype2-demos] master 8969c8a 24/41: [ftinspect] Add left/right click


From: Werner Lemberg
Subject: [freetype2-demos] master 8969c8a 24/41: [ftinspect] Add left/right click behaviour to the continuous view.
Date: Mon, 3 Oct 2022 11:27:02 -0400 (EDT)

branch: master
commit 8969c8a24a9d576a3ce8295010390ea41b4d85bc
Author: Charlie Jiang <w@chariri.moe>
Commit: Werner Lemberg <wl@gnu.org>

    [ftinspect] Add left/right click behaviour to the continuous view.
    
    Left clicking will open the glyph details pane, and right clicking will
    switch to the singular tab.
    
    * src/ftinspect/panels/glyphdetails.cpp,
      src/ftinspect/panels/glyphdetails.hpp:
      New files, add the `GlyphDetails` class.
    
    * src/ftinspect/glyphcomponents/glyphcontinuous.cpp,
      src/ftinspect/glyphcomponents/glyphcontinuous.hpp:
      Add `mouseReleaseEvent` event handler which emits the new
      `updateGlyphDetails` and `rightClickGlyph` signals.
    
    * src/ftinspect/glyphcomponents/glyphbitmap.cpp,
      src/ftinspect/glyphcomponents/glyphbitmap.hpp:
      Add `GlyphBitmapWidget` to show the enlarged bitmap.
    
    * src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
      Add code to update the details panel, and wire up events.
    
    * src/ftinspect/maingui.cpp, src/ftinspect/maingui.hpp:
      Add code to initialize the glyph details panel, and wire up components and
      events.
    
    * src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
---
 src/ftinspect/CMakeLists.txt                      |   1 +
 src/ftinspect/glyphcomponents/glyphbitmap.cpp     |  82 +++++++
 src/ftinspect/glyphcomponents/glyphbitmap.hpp     |  26 ++
 src/ftinspect/glyphcomponents/glyphcontinuous.cpp |  25 ++
 src/ftinspect/glyphcomponents/glyphcontinuous.hpp |   3 +
 src/ftinspect/maingui.cpp                         |  38 ++-
 src/ftinspect/maingui.hpp                         |   6 +
 src/ftinspect/meson.build                         |   3 +
 src/ftinspect/panels/continuous.cpp               |  27 ++-
 src/ftinspect/panels/continuous.hpp               |  15 +-
 src/ftinspect/panels/glyphdetails.cpp             | 274 ++++++++++++++++++++++
 src/ftinspect/panels/glyphdetails.hpp             |  94 ++++++++
 12 files changed, 590 insertions(+), 4 deletions(-)

diff --git a/src/ftinspect/CMakeLists.txt b/src/ftinspect/CMakeLists.txt
index 098f331..ace3301 100644
--- a/src/ftinspect/CMakeLists.txt
+++ b/src/ftinspect/CMakeLists.txt
@@ -49,6 +49,7 @@ add_executable(ftinspect
   "panels/settingpanelmmgx.cpp"
   "panels/singular.cpp"
   "panels/continuous.cpp"
+  "panels/glyphdetails.cpp"
 )
 target_link_libraries(ftinspect
   Qt5::Core Qt5::Widgets
diff --git a/src/ftinspect/glyphcomponents/glyphbitmap.cpp 
b/src/ftinspect/glyphcomponents/glyphbitmap.cpp
index a25b5a1..90a0b81 100644
--- a/src/ftinspect/glyphcomponents/glyphbitmap.cpp
+++ b/src/ftinspect/glyphcomponents/glyphbitmap.cpp
@@ -87,6 +87,88 @@ GlyphBitmap::paint(QPainter* painter,
                                qAlpha(p)));
     }
 #endif
+
+}
+
+
+GlyphBitmapWidget::GlyphBitmapWidget(QWidget* parent)
+: QWidget(parent)
+{
+  setToolTip(tr("Click to inspect in Singular Grid View."));
+}
+
+
+GlyphBitmapWidget::~GlyphBitmapWidget()
+{
+  delete bitmapItem_;
+  bitmapItem_ = NULL;
+}
+
+
+void
+GlyphBitmapWidget::updateImage(QImage* image,
+                               QRect rect)
+{
+  rect.moveTop(0);
+  rect.moveLeft(0);
+
+  delete bitmapItem_;
+  auto* copied = new QImage(image->copy());
+  bitmapItem_ = new GlyphBitmap(copied, rect);
+
+  repaint();
+}
+
+
+void
+GlyphBitmapWidget::releaseImage()
+{
+  delete bitmapItem_;
+  bitmapItem_ = NULL;
+  repaint();
+}
+
+
+void
+GlyphBitmapWidget::paintEvent(QPaintEvent* event)
+{
+  if (!bitmapItem_)
+    return;
+  auto s = size();
+  auto br = bitmapItem_->boundingRect();
+  double xScale = s.width() / br.width();
+  double yScale = s.height() / br.height();
+  auto scale = std::min(xScale, yScale);
+
+  QPainter painter(this);
+  painter.fillRect(rect(), Qt::white);
+  painter.scale(scale, scale);
+
+  QStyleOptionGraphicsItem ogi;
+  ogi.exposedRect = br;
+  bitmapItem_->paint(&painter, &ogi, this);
+
+  double scaledLineWidth = 4 / scale;
+  painter.setPen(QPen(Qt::black, scaledLineWidth));
+  scaledLineWidth /= 2;
+  painter.drawRect(br.adjusted(scaledLineWidth, scaledLineWidth,
+                               -scaledLineWidth, -scaledLineWidth));
+}
+
+
+QSize
+GlyphBitmapWidget::sizeHint() const
+{
+  return { 300, 300 };
+}
+
+
+void
+GlyphBitmapWidget::mouseReleaseEvent(QMouseEvent* event)
+{
+  QWidget::mouseReleaseEvent(event);
+  if (event->button() == Qt::LeftButton)
+    emit clicked();
 }
 
 
diff --git a/src/ftinspect/glyphcomponents/glyphbitmap.hpp 
b/src/ftinspect/glyphcomponents/glyphbitmap.hpp
index d2dafd7..52cfd22 100644
--- a/src/ftinspect/glyphcomponents/glyphbitmap.hpp
+++ b/src/ftinspect/glyphcomponents/glyphbitmap.hpp
@@ -39,4 +39,30 @@ private:
 };
 
 
+// Sometimes we don't want a complicated QGraphicsView
+// for this kind of work...
+class GlyphBitmapWidget
+: public QWidget
+{
+  Q_OBJECT
+public:
+  GlyphBitmapWidget(QWidget* parent);
+  ~GlyphBitmapWidget() override;
+
+  void updateImage(QImage* image, QRect rect);
+  void releaseImage();
+
+signals:
+  void clicked();
+
+protected:
+  void paintEvent(QPaintEvent* event) override;
+  QSize sizeHint() const override;
+  void mouseReleaseEvent(QMouseEvent* event) override;
+
+private:
+  GlyphBitmap* bitmapItem_ = NULL;
+};
+
+
 // end of glyphbitmap.hpp
diff --git a/src/ftinspect/glyphcomponents/glyphcontinuous.cpp 
b/src/ftinspect/glyphcomponents/glyphcontinuous.cpp
index 37f7db5..ebdac27 100644
--- a/src/ftinspect/glyphcomponents/glyphcontinuous.cpp
+++ b/src/ftinspect/glyphcomponents/glyphcontinuous.cpp
@@ -220,6 +220,31 @@ GlyphContinuous::mouseMoveEvent(QMouseEvent* event)
 }
 
 
+void
+GlyphContinuous::mouseReleaseEvent(QMouseEvent* event)
+{
+  if (!mouseOperationEnabled_)
+    return;
+  if (event->button() == Qt::LeftButton)
+  {
+    auto dist = event->pos() - mouseDownPostition_;
+    if (dist.manhattanLength() < ClickDragThreshold)
+    {
+      auto gl = findGlyphByMouse(event->pos(), NULL);
+      if (gl)
+        emit updateGlyphDetails(gl, stringRenderer_.charMapIndex(), true);
+    }
+  }
+  else if (event->button() == Qt::RightButton)
+  {
+    double size;
+    auto gl = findGlyphByMouse(event->pos(), &size);
+    if (gl)
+      emit rightClickGlyph(gl->glyphIndex, size);
+  }
+}
+
+
 void
 GlyphContinuous::paintByRenderer()
 {
diff --git a/src/ftinspect/glyphcomponents/glyphcontinuous.hpp 
b/src/ftinspect/glyphcomponents/glyphcontinuous.hpp
index 7366de9..87c822c 100644
--- a/src/ftinspect/glyphcomponents/glyphcontinuous.hpp
+++ b/src/ftinspect/glyphcomponents/glyphcontinuous.hpp
@@ -107,6 +107,8 @@ signals:
   void wheelZoom(int steps);
   void beginIndexChangeRequest(int newIndex);
   void displayingCountUpdated(int newCount);
+  void rightClickGlyph(int glyphIndex, double sizePoint);
+  void updateGlyphDetails(GlyphCacheEntry* ctxt, int charMapIndex, bool open);
 
 protected:
   void paintEvent(QPaintEvent* event) override;
@@ -114,6 +116,7 @@ protected:
   void resizeEvent(QResizeEvent* event) override;
   void mousePressEvent(QMouseEvent* event) override;
   void mouseMoveEvent(QMouseEvent* event) override;
+  void mouseReleaseEvent(QMouseEvent* event) override;
 
 private:
   Engine* engine_;
diff --git a/src/ftinspect/maingui.cpp b/src/ftinspect/maingui.cpp
index b4a38dc..c08e01a 100644
--- a/src/ftinspect/maingui.cpp
+++ b/src/ftinspect/maingui.cpp
@@ -175,6 +175,22 @@ MainGUI::switchTab()
 }
 
 
+void
+MainGUI::switchToSingular(int glyphIndex,
+                          double sizePoint)
+{
+  tabWidget_->setCurrentWidget(singularTab_); // this would update the tab
+  singularTab_->setCurrentGlyphAndSize(glyphIndex, sizePoint);
+}
+
+
+void
+MainGUI::closeDockWidget()
+{
+  glyphDetailsDockWidget_->hide();
+}
+
+
 void
 MainGUI::repaintCurrentTab()
 {
@@ -206,6 +222,13 @@ MainGUI::applySettings()
 void
 MainGUI::createLayout()
 {
+  // floating
+  glyphDetailsDockWidget_ = new QDockWidget(tr("Glyph Details"), this);
+  glyphDetails_ = new GlyphDetails(glyphDetailsDockWidget_, engine_);
+  glyphDetailsDockWidget_->setWidget(glyphDetails_);
+  glyphDetailsDockWidget_->setFloating(true);
+  glyphDetailsDockWidget_->hide();
+
   // left side
   settingPanel_ = new SettingPanel(this, engine_);
 
@@ -221,7 +244,8 @@ MainGUI::createLayout()
 
   // right side
   singularTab_ = new SingularTab(this, engine_);
-  continuousTab_ = new ContinuousTab(this, engine_);
+  continuousTab_ = new ContinuousTab(this, engine_,
+                                     glyphDetailsDockWidget_, glyphDetails_);
 
   tabWidget_ = new QTabWidget(this);
   tabWidget_->setObjectName("mainTab"); // for stylesheet
@@ -287,6 +311,18 @@ MainGUI::createConnections()
 
   connect(tripletSelector_, &TripletSelector::tripletChanged,
           this, &MainGUI::onTripletChanged);
+
+  connect(continuousTab_, &ContinuousTab::switchToSingular,
+          this, &MainGUI::switchToSingular);
+  connect(glyphDetails_, &GlyphDetails::closeDockWidget, 
+          this, &MainGUI::closeDockWidget);
+  connect(glyphDetails_, &GlyphDetails::switchToSingular,
+          [&] (int index)
+          {
+            switchToSingular(index, -1);
+            if (glyphDetailsDockWidget_->isFloating())
+              glyphDetailsDockWidget_->hide();
+          });
 }
 
 
diff --git a/src/ftinspect/maingui.hpp b/src/ftinspect/maingui.hpp
index 44c6014..d375231 100644
--- a/src/ftinspect/maingui.hpp
+++ b/src/ftinspect/maingui.hpp
@@ -11,6 +11,7 @@
 #include "panels/abstracttab.hpp"
 #include "panels/singular.hpp"
 #include "panels/continuous.hpp"
+#include "panels/glyphdetails.hpp"
 
 #include <vector>
 #include <QAction>
@@ -54,6 +55,8 @@ private slots:
   void loadFonts();
   void onTripletChanged();
   void switchTab();
+  void switchToSingular(int glyphIndex, double sizePoint);
+  void closeDockWidget();
 
 private:
   Engine* engine_;
@@ -92,6 +95,9 @@ private:
   ContinuousTab* continuousTab_;
   QWidget* lastTab_ = NULL;
 
+  QDockWidget* glyphDetailsDockWidget_;
+  GlyphDetails* glyphDetails_;
+
   void openFonts(QStringList const& fileNames);
 
   void applySettings();
diff --git a/src/ftinspect/meson.build b/src/ftinspect/meson.build
index 392ec8a..9167e8b 100644
--- a/src/ftinspect/meson.build
+++ b/src/ftinspect/meson.build
@@ -50,6 +50,7 @@ if qt5_dep.found()
     'panels/settingpanelmmgx.cpp',
     'panels/singular.cpp',
     'panels/continuous.cpp',
+    'panels/glyphdetails.cpp',
 
     'ftinspect.cpp',
     'maingui.cpp',
@@ -59,6 +60,7 @@ if qt5_dep.found()
   moc_files = qt5.preprocess(
     moc_headers: [
       'engine/fontfilemanager.hpp',
+      'glyphcomponents/glyphbitmap.hpp',
       'glyphcomponents/glyphcontinuous.hpp',
       'widgets/customwidgets.hpp',
       'widgets/tripletselector.hpp',
@@ -71,6 +73,7 @@ if qt5_dep.found()
       'panels/settingpanelmmgx.hpp',
       'panels/singular.hpp',
       'panels/continuous.hpp',
+      'panels/glyphdetails.hpp',
     ],
     dependencies: qt5_dep)
 
diff --git a/src/ftinspect/panels/continuous.cpp 
b/src/ftinspect/panels/continuous.cpp
index c10a7ef..ef52034 100644
--- a/src/ftinspect/panels/continuous.cpp
+++ b/src/ftinspect/panels/continuous.cpp
@@ -4,6 +4,7 @@
 
 #include "continuous.hpp"
 
+#include "glyphdetails.hpp"
 #include "../uihelper.hpp"
 
 #include <climits>
@@ -12,9 +13,13 @@
 
 
 ContinuousTab::ContinuousTab(QWidget* parent,
-                             Engine* engine)
+                             Engine* engine,
+                             QDockWidget* gdWidget,
+                             GlyphDetails* glyphDetails)
 : QWidget(parent),
-  engine_(engine)
+  engine_(engine),
+  glyphDetailsWidget_(gdWidget),
+  glyphDetails_(glyphDetails)
 {
   createLayout();
 
@@ -228,6 +233,20 @@ ContinuousTab::reloadGlyphsAndRepaint()
 }
 
 
+void
+ContinuousTab::updateGlyphDetails(GlyphCacheEntry* ctxt,
+                                  int charMapIndex,
+                                  bool open)
+{
+  glyphDetails_->updateGlyph(*ctxt, charMapIndex);
+  if (open)
+  {
+    glyphDetailsWidget_->show();
+    glyphDetailsWidget_->activateWindow();
+  }
+}
+
+
 void
 ContinuousTab::openWaterfallConfig()
 {
@@ -467,8 +486,12 @@ ContinuousTab::createConnections()
           this, &ContinuousTab::wheelZoom);
   connect(canvas_, &GlyphContinuous::displayingCountUpdated, 
           indexSelector_, &GlyphIndexSelector::setShowingCount);
+  connect(canvas_, &GlyphContinuous::rightClickGlyph, 
+          this, &ContinuousTab::switchToSingular);
   connect(canvas_, &GlyphContinuous::beginIndexChangeRequest, 
           this, &ContinuousTab::setGlyphBeginindex);
+  connect(canvas_, &GlyphContinuous::updateGlyphDetails, 
+          this, &ContinuousTab::updateGlyphDetails);
 
   connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
           this, &ContinuousTab::repaintGlyph);
diff --git a/src/ftinspect/panels/continuous.hpp 
b/src/ftinspect/panels/continuous.hpp
index deec32a..2daaa9f 100644
--- a/src/ftinspect/panels/continuous.hpp
+++ b/src/ftinspect/panels/continuous.hpp
@@ -22,15 +22,18 @@
 #include <QGridLayout>
 #include <QBoxLayout>
 #include <QPlainTextEdit>
+#include <QDockWidget>
 #include <QCheckBox>
 
+class GlyphDetails;
 class WaterfallConfigDialog;
 class ContinuousTab
 : public QWidget, public AbstractTab
 {
   Q_OBJECT
 public:
-  ContinuousTab(QWidget* parent, Engine* engine);
+  ContinuousTab(QWidget* parent, Engine* engine,
+                QDockWidget* gdWidget, GlyphDetails* glyphDetails);
   ~ContinuousTab() override = default;
 
   void repaintGlyph() override;
@@ -38,6 +41,10 @@ public:
   void highlightGlyph(int index);
   void applySettings();
 
+signals:
+  // if sizePoint <= 0, then don't change size.
+  void switchToSingular(int glyphIndex, double sizePoint);
+
 protected:
   bool eventFilter(QObject* watched, QEvent* event) override;
   
@@ -88,6 +95,9 @@ private:
   QGridLayout* bottomLayout_;
   QVBoxLayout* mainLayout_;
 
+  QDockWidget* glyphDetailsWidget_;
+  GlyphDetails* glyphDetails_;
+
   WaterfallConfigDialog* wfConfigDialog_;
 
   void createLayout();
@@ -106,6 +116,9 @@ private:
   void sourceTextChanged();
   void presetStringSelected();
   void reloadGlyphsAndRepaint();
+  void updateGlyphDetails(GlyphCacheEntry* ctxt, 
+                          int charMapIndex, 
+                          bool open);
   void openWaterfallConfig();
   void showToolTip();
 
diff --git a/src/ftinspect/panels/glyphdetails.cpp 
b/src/ftinspect/panels/glyphdetails.cpp
new file mode 100644
index 0000000..c412029
--- /dev/null
+++ b/src/ftinspect/panels/glyphdetails.cpp
@@ -0,0 +1,274 @@
+// glyphdetails.cpp
+
+// Copyright (C) 2022 by Charlie Jiang.
+
+#include "glyphdetails.hpp"
+
+#include "../engine/stringrenderer.hpp"
+#include "../glyphcomponents/glyphcontinuous.hpp"
+#include "../uihelper.hpp"
+#include "../engine/engine.hpp"
+
+
+GlyphDetails::GlyphDetails(QWidget* parent,
+                           Engine* engine)
+: QWidget(parent),
+  engine_(engine)
+{
+  createLayout();
+  createConnections();
+}
+
+
+GlyphDetails::~GlyphDetails()
+{
+}
+
+
+void
+GlyphDetails::updateGlyph(GlyphCacheEntry& ctxt, int charMapIndex)
+{
+  auto& cMaps = engine_->currentFontCharMaps();
+
+  glyphIndex_ = ctxt.glyphIndex;
+  glyphIndexLabel_->setText(QString::number(ctxt.glyphIndex));
+  if (charMapIndex < 0 || static_cast<unsigned>(charMapIndex) >= cMaps.size())
+  {
+    charCodePromptLabel_->setVisible(false);
+    charCodeLabel_->setVisible(false);
+  }
+  else
+  {
+    charCodePromptLabel_->setVisible(true);
+    charCodeLabel_->setVisible(true);
+    charCodeLabel_->setText(
+        cMaps[charMapIndex].stringifyIndexShort(ctxt.charCode));
+  }
+
+  auto glyphName = engine_->glyphName(ctxt.glyphIndex);
+  if (glyphName.isEmpty())
+    glyphName = "(none)";
+  glyphNameLabel_->setText(glyphName);
+
+  auto rect = ctxt.basePosition.translated(-(ctxt.penPos.x()),
+                                           -(ctxt.penPos.y()));
+  bitmapWidget_->updateImage(ctxt.image, rect);
+
+  // load glyphs in all units
+  dpi_ = engine_->dpi();
+  engine_->reloadFont();
+
+  engine_->loadGlyphIntoSlotWithoutCache(ctxt.glyphIndex, true);
+  fontUnitMetrics_ = engine_->currentFaceSlot()->metrics;
+  engine_->loadGlyphIntoSlotWithoutCache(ctxt.glyphIndex, false);
+  pixelMetrics_ = engine_->currentFaceSlot()->metrics;
+
+  changeUnit(unitButtonGroup_->checkedId());
+
+  inkSizeLabel_->setText(QString("(%1, %2) px")
+                                 .arg(rect.width())
+                                 .arg(rect.height()));
+  bitmapOffsetLabel_->setText(QString("(%1, %2) px")
+                                    .arg(rect.x())
+                                    .arg(rect.y()));
+}
+
+
+void
+GlyphDetails::keyReleaseEvent(QKeyEvent* event)
+{
+  if (event->key() == Qt::Key_Escape)
+    emit closeDockWidget();
+  else
+    QWidget::keyReleaseEvent(event);
+}
+
+
+void
+GlyphDetails::createLayout()
+{
+  unitButtonGroup_ = new QButtonGroup(this);
+  fontUnitButton_ = new QRadioButton(tr("Font Unit"), this);
+  pointButton_ = new QRadioButton(tr("Point"), this);
+  pixelButton_ = new QRadioButton(tr("Pixel"), this);
+  unitButtonGroup_->addButton(fontUnitButton_, DU_FontUnit);
+  unitButtonGroup_->addButton(pointButton_, DU_Point);
+  unitButtonGroup_->addButton(pixelButton_, DU_Pixel);
+  fontUnitButton_->setChecked(true);
+
+  glyphIndexPromptLabel_ = new QLabel(tr("Grid Index:"), this);
+  charCodePromptLabel_ = new QLabel(tr("Char Code:"), this);
+  glyphNamePromptLabel_ = new QLabel(tr("Glyph Name:"), this);
+
+  bboxSizePromptLabel_ = new QLabel(tr("Bounding Box Size:"), this);
+  horiBearingPromptLabel_ = new QLabel(tr("Hori. Bearing:"), this);
+  horiAdvancePromptLabel_ = new QLabel(tr("Hori. Advance:"), this);
+  vertBearingPromptLabel_ = new QLabel(tr("Vert. Bearing:"), this);
+  vertAdvancePromptLabel_ = new QLabel(tr("Vert. Advance:"), this);
+
+  inkSizePromptLabel_ = new QLabel(tr("Ink Size:"), this);
+  bitmapOffsetPromptLabel_ = new QLabel(tr("Bitmap Offset:"), this);
+
+  glyphIndexLabel_ = new QLabel(this);
+  charCodeLabel_ = new QLabel(this);
+  glyphNameLabel_ = new QLabel(this);
+
+  bboxSizeLabel_ = new QLabel(this);
+  horiBearingLabel_ = new QLabel(this);
+  horiAdvanceLabel_ = new QLabel(this);
+  vertBearingLabel_ = new QLabel(this);
+  vertAdvanceLabel_ = new QLabel(this);
+
+  inkSizeLabel_ = new QLabel(this);
+  bitmapOffsetLabel_ = new QLabel(this);
+
+  bitmapWidget_ = new GlyphBitmapWidget(this);
+
+  setLabelSelectable(glyphIndexLabel_);
+  setLabelSelectable(charCodeLabel_);
+  setLabelSelectable(glyphNameLabel_);
+  setLabelSelectable(bboxSizeLabel_);
+  setLabelSelectable(horiBearingLabel_);
+  setLabelSelectable(horiAdvanceLabel_);
+  setLabelSelectable(vertBearingLabel_);
+  setLabelSelectable(vertAdvanceLabel_);
+  setLabelSelectable(inkSizeLabel_);
+  setLabelSelectable(bitmapOffsetLabel_);
+
+  // Tooltips
+  fontUnitButton_->setToolTip(tr("Unit for most metrics entries below"));
+  pointButton_   ->setToolTip(tr("Unit for most metrics entries below"));
+  pixelButton_   ->setToolTip(tr("Unit for most metrics entries below"));
+  bboxSizeLabel_->setToolTip(
+    tr("Glyph bounding box (in unit specified above)"));
+  horiBearingLabel_->setToolTip(
+    tr("Bearing for horizontal layout (in unit specified above)"));
+  horiAdvanceLabel_->setToolTip(
+    tr("Advance for horizontal layout (in unit specified above)"));
+  vertBearingLabel_->setToolTip(
+    tr("Bearing for vertical layout (in unit specified above)"));
+  vertAdvanceLabel_->setToolTip(
+    tr("Advance for vertical layout (in unit specified above)"));
+  inkSizeLabel_->setToolTip(
+    tr("The tightest bounding box size (always in pixels)"));
+  bitmapOffsetLabel_->setToolTip(
+    tr("Offset from the most top-left point to the bitmap (always in 
pixels)"));
+  bitmapWidget_->setToolTip(tr("Bitmap preview"));
+
+  // Layouting
+  unitLayout_ = new QHBoxLayout;
+  unitLayout_->addWidget(fontUnitButton_);
+  unitLayout_->addWidget(pointButton_);
+  unitLayout_->addWidget(pixelButton_);
+
+  layout_ = new QGridLayout;
+  gridLayout2ColAddLayout(layout_, unitLayout_);
+  gridLayout2ColAddItem(layout_, new QSpacerItem(0, 18));
+
+  gridLayout2ColAddWidget(layout_, glyphIndexPromptLabel_, glyphIndexLabel_);
+  gridLayout2ColAddWidget(layout_, charCodePromptLabel_  , charCodeLabel_  );
+  gridLayout2ColAddWidget(layout_, glyphNamePromptLabel_ , glyphNameLabel_ );
+  gridLayout2ColAddItem(layout_, new QSpacerItem(0, 18));
+
+  gridLayout2ColAddWidget(layout_, bboxSizePromptLabel_,    bboxSizeLabel_  );
+  gridLayout2ColAddWidget(layout_, horiBearingPromptLabel_, horiBearingLabel_);
+  gridLayout2ColAddWidget(layout_, horiAdvancePromptLabel_, horiAdvanceLabel_);
+  gridLayout2ColAddWidget(layout_, vertBearingPromptLabel_, vertBearingLabel_);
+  gridLayout2ColAddWidget(layout_, vertAdvancePromptLabel_, vertAdvanceLabel_);
+  gridLayout2ColAddItem(layout_, new QSpacerItem(0, 18));
+
+  gridLayout2ColAddWidget(layout_, inkSizePromptLabel_, inkSizeLabel_);
+  gridLayout2ColAddWidget(layout_, bitmapOffsetPromptLabel_, 
+                                   bitmapOffsetLabel_);
+  gridLayout2ColAddItem(layout_, new QSpacerItem(0, 18));
+
+  auto bmapRowPos = gridLayout2ColAddWidget(layout_, bitmapWidget_);
+
+  layout_->setColumnStretch(1, 1);
+  layout_->setRowStretch(bmapRowPos, 1);
+
+  setLayout(layout_);
+  setContentsMargins(12, 12, 12, 12);
+  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+
+void
+GlyphDetails::createConnections()
+{
+  connect(unitButtonGroup_, &QButtonGroup::idClicked,
+          this, &GlyphDetails::changeUnit);
+
+  connect(bitmapWidget_, &GlyphBitmapWidget::clicked,
+          this, &GlyphDetails::bitmapWidgetClicked);
+}
+
+
+void
+GlyphDetails::changeUnit(int unitId)
+{
+  QString unitSuffix;
+  double bboxW = -1, bboxH = -1;
+  double horiBearingX = -1, horiBearingY = -1;
+  double horiAdvance = -1;
+  double vertBearingX = -1, vertBearingY = -1;
+  double vertAdvance = -1;
+  switch (static_cast<DisplayUnit>(unitId))
+  {
+  case DU_FontUnit:
+    unitSuffix = "";
+    bboxW = fontUnitMetrics_.width;
+    bboxH = fontUnitMetrics_.height;
+    horiBearingX = fontUnitMetrics_.horiBearingX;
+    horiBearingY = fontUnitMetrics_.horiBearingY;
+    horiAdvance = fontUnitMetrics_.horiAdvance;
+    vertBearingX = fontUnitMetrics_.vertBearingX;
+    vertBearingY = fontUnitMetrics_.vertBearingY;
+    vertAdvance = fontUnitMetrics_.vertAdvance;
+    break;
+
+  case DU_Point:
+    unitSuffix = " pt";
+    // 1.125 = 72 / 64
+    bboxW = pixelMetrics_.width * 1.125 / dpi_;
+    bboxH = pixelMetrics_.height * 1.125 / dpi_;
+    horiBearingX = pixelMetrics_.horiBearingX * 1.125 / dpi_;
+    horiBearingY = pixelMetrics_.horiBearingY * 1.125 / dpi_;
+    horiAdvance = pixelMetrics_.horiAdvance * 1.125 / dpi_;
+    vertBearingX = pixelMetrics_.vertBearingX * 1.125 / dpi_;
+    vertBearingY = pixelMetrics_.vertBearingY * 1.125 / dpi_;
+    vertAdvance = pixelMetrics_.vertAdvance * 1.125 / dpi_;
+    break;
+    
+  case DU_Pixel:
+    unitSuffix = " px";
+    bboxW = pixelMetrics_.width/ 64.0;
+    bboxH = pixelMetrics_.height/ 64.0;
+    horiBearingX = pixelMetrics_.horiBearingX/ 64.0;
+    horiBearingY = pixelMetrics_.horiBearingY/ 64.0;
+    horiAdvance = pixelMetrics_.horiAdvance/ 64.0;
+    vertBearingX = pixelMetrics_.vertBearingX/ 64.0;
+    vertBearingY = pixelMetrics_.vertBearingY/ 64.0;
+    vertAdvance = pixelMetrics_.vertAdvance/ 64.0;
+    break;
+  }
+
+  auto tmpl = QString("%1") + unitSuffix;
+  auto tmplPair = QString("(%1, %2)") + unitSuffix;
+  bboxSizeLabel_->setText(tmplPair.arg(bboxW).arg(bboxH));
+  horiBearingLabel_->setText(tmplPair.arg(horiBearingX).arg(horiBearingY));
+  horiAdvanceLabel_->setText(tmpl.arg(horiAdvance));
+  vertBearingLabel_->setText(tmplPair.arg(vertBearingX).arg(vertBearingY));
+  vertAdvanceLabel_->setText(tmpl.arg(vertAdvance));
+}
+
+
+void
+GlyphDetails::bitmapWidgetClicked()
+{
+  if (glyphIndex_ >= 0)
+    emit switchToSingular(glyphIndex_);
+}
+
+
+// end of glyphdetails.cpp
diff --git a/src/ftinspect/panels/glyphdetails.hpp 
b/src/ftinspect/panels/glyphdetails.hpp
new file mode 100644
index 0000000..99b6139
--- /dev/null
+++ b/src/ftinspect/panels/glyphdetails.hpp
@@ -0,0 +1,94 @@
+// glyphdetails.hpp
+
+// Copyright (C) 2022 by Charlie Jiang.
+
+#pragma once
+
+#include "../glyphcomponents/glyphbitmap.hpp"
+
+#include <QWidget>
+#include <QLabel>
+#include <QGridLayout>
+#include <QBoxLayout>
+#include <QImage>
+#include <QRadioButton>
+#include <QButtonGroup>
+
+#include <freetype/freetype.h>
+
+struct GlyphCacheEntry;
+class Engine;
+class GlyphDetails
+: public QWidget
+{
+  Q_OBJECT
+
+public:
+  GlyphDetails(QWidget* parent, Engine* engine);
+  ~GlyphDetails() override;
+
+  void updateGlyph(GlyphCacheEntry& ctxt,
+                   int charMapIndex);
+
+signals:
+  void switchToSingular(int index);
+  void closeDockWidget();
+
+protected:
+  void keyReleaseEvent(QKeyEvent* event) override;
+
+private:
+  Engine* engine_ = NULL;
+  int glyphIndex_ = -1;
+
+  enum DisplayUnit : int
+  {
+    DU_FontUnit,
+    DU_Point,
+    DU_Pixel
+  };
+
+  QButtonGroup* unitButtonGroup_;
+  QRadioButton* fontUnitButton_;
+  QRadioButton* pointButton_;
+  QRadioButton* pixelButton_;
+
+  QLabel* glyphIndexPromptLabel_;
+  QLabel* charCodePromptLabel_;
+  QLabel* glyphNamePromptLabel_;
+  QLabel* bboxSizePromptLabel_;
+  QLabel* horiBearingPromptLabel_;
+  QLabel* horiAdvancePromptLabel_;
+  QLabel* vertBearingPromptLabel_;
+  QLabel* vertAdvancePromptLabel_;
+  QLabel* inkSizePromptLabel_;
+  QLabel* bitmapOffsetPromptLabel_;
+
+  QLabel* glyphIndexLabel_;
+  QLabel* charCodeLabel_;
+  QLabel* glyphNameLabel_;
+  QLabel* bboxSizeLabel_;
+  QLabel* horiBearingLabel_;
+  QLabel* horiAdvanceLabel_;
+  QLabel* vertBearingLabel_;
+  QLabel* vertAdvanceLabel_;
+  QLabel* inkSizeLabel_;
+  QLabel* bitmapOffsetLabel_;
+
+  GlyphBitmapWidget* bitmapWidget_;
+
+  QHBoxLayout* unitLayout_;
+  QGridLayout* layout_;
+
+  int dpi_;
+  FT_Glyph_Metrics fontUnitMetrics_, pixelMetrics_;
+
+  void createLayout();
+  void createConnections();
+
+  void changeUnit(int unitId);
+  void bitmapWidgetClicked();
+};
+
+
+// end of glyphdetails.hpp



reply via email to

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