blob: 1d7cef1e21b4445570ce2fdabd371354b8ec8244 [file] [log] [blame]
#include <QDebug>
#include <QMouseEvent>
#include <QPainter>
#include <QScrollBar>
#include <cmath>
#include "glyphsview.h"
static const int COLUMNS_COUNT = 100;
GlyphsView::GlyphsView(QWidget *parent) : QAbstractScrollArea(parent)
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}
void GlyphsView::setFontInfo(const FontInfo &fi)
{
m_fontInfo = fi;
m_glyphs.resize(fi.numberOfGlyphs);
#ifdef WITH_FREETYPE
m_ftGlyphs.resize(fi.numberOfGlyphs);
#endif
#ifdef WITH_HARFBUZZ
m_hbGlyphs.resize(fi.numberOfGlyphs);
#endif
m_indexes.clear();
for (int i = 0; i < fi.numberOfGlyphs; ++i) {
QStaticText text(QString::number(i));
text.prepare();
m_indexes << text;
}
updateScrollBars();
horizontalScrollBar()->setValue(0);
verticalScrollBar()->setValue(0);
}
void GlyphsView::setGlyph(int idx, const Glyph &glyph)
{
m_glyphs.replace(idx, glyph);
}
#ifdef WITH_FREETYPE
void GlyphsView::setFTGlyph(int idx, const Glyph &glyph)
{
m_ftGlyphs.replace(idx, glyph);
}
#endif
#ifdef WITH_HARFBUZZ
void GlyphsView::setHBGlyph(int idx, const Glyph &glyph)
{
m_hbGlyphs.replace(idx, glyph);
}
#endif
void GlyphsView::setDrawBboxes(const bool flag)
{
m_drawBboxes = flag;
viewport()->update();
}
void GlyphsView::setDrawGlyphs(const bool flag)
{
m_drawGlyphs = flag;
viewport()->update();
}
void GlyphsView::setDrawFTGlyphs(const bool flag)
{
m_drawFTGlyphs = flag;
viewport()->update();
}
void GlyphsView::setDrawHBGlyphs(const bool flag)
{
m_drawHBGlyphs = flag;
viewport()->update();
}
void GlyphsView::paintEvent(QPaintEvent *)
{
QPainter p(viewport());
p.translate(-horizontalScrollBar()->value(), -verticalScrollBar()->value());
const double cellHeight = m_fontInfo.height * m_scale;
drawGrid(p, cellHeight);
p.setRenderHint(QPainter::Antialiasing);
{
auto font = p.font();
font.setPointSize(10);
p.setFont(font);
}
int x = 0;
int y = m_fontInfo.ascender;
int num_y = m_fontInfo.height;
for (int i = 0; i < m_glyphs.size(); ++i) {
// Text rendering is the slowest part, so we are using preprocessed text.
p.setPen(palette().color(QPalette::Text));
p.drawStaticText(
qRound(x * m_scale + 1),
qRound(num_y * m_scale - p.fontMetrics().ascent() - 2),
m_indexes.at(i)
);
if (m_drawGlyphs) {
p.save();
const int dx = qRound((m_fontInfo.height - m_glyphs.at(i).bbox.width()) / 2.0)
- m_glyphs.at(i).bbox.x();
p.scale(m_scale, m_scale);
p.translate(x + dx, y);
if (m_drawBboxes) {
p.setPen(QPen(Qt::darkGreen, 0.5 / m_scale));
p.setBrush(Qt::NoBrush);
p.drawRect(m_glyphs.at(i).bbox);
}
p.setPen(Qt::NoPen);
p.setPen(Qt::NoPen);
if (m_drawFTGlyphs || m_drawHBGlyphs) {
p.setBrush(Qt::red);
} else {
p.setBrush(palette().color(QPalette::Text));
}
p.drawPath(m_glyphs.at(i).outline);
p.restore();
}
#ifdef WITH_HARFBUZZ
if (m_drawHBGlyphs) {
p.save();
const int dx = qRound((m_fontInfo.height - m_hbGlyphs.at(i).bbox.width()) / 2.0)
- m_hbGlyphs.at(i).bbox.x();
p.scale(m_scale, m_scale);
p.translate(x + dx, y);
if (m_drawBboxes) {
p.setPen(QPen(Qt::darkGreen, 0.5 / m_scale));
p.setBrush(Qt::NoBrush);
p.drawRect(m_hbGlyphs.at(i).bbox);
}
p.setPen(Qt::NoPen);
if (m_drawFTGlyphs) {
p.setBrush(Qt::blue);
} else {
p.setBrush(palette().color(QPalette::Text));
}
p.drawPath(m_hbGlyphs.at(i).outline);
p.restore();
}
#endif
#ifdef WITH_FREETYPE
if (m_drawFTGlyphs) {
p.save();
const int dx = qRound((m_fontInfo.height - m_ftGlyphs.at(i).bbox.width()) / 2.0)
- m_ftGlyphs.at(i).bbox.x();
p.scale(m_scale, m_scale);
p.translate(x + dx, y);
if (m_drawBboxes) {
p.setPen(QPen(Qt::darkGreen, 0.5 / m_scale));
p.setBrush(Qt::NoBrush);
p.drawRect(m_ftGlyphs.at(i).bbox);
}
p.setPen(Qt::NoPen);
p.setBrush(palette().color(QPalette::Text));
if (m_drawGlyphs || m_drawHBGlyphs) {
p.setBrush(palette().color(QPalette::Base));
}
p.drawPath(m_ftGlyphs.at(i).outline);
p.restore();
}
#endif
x += m_fontInfo.height;
if (i > 0 && (i + 1) % COLUMNS_COUNT == 0) {
x = 0;
y += m_fontInfo.height;
num_y += m_fontInfo.height;
}
}
}
void GlyphsView::drawGrid(QPainter &p, const double cellHeight)
{
p.setRenderHint(QPainter::Antialiasing, false);
p.setPen(QPen(palette().color(QPalette::Text), 0.25));
p.setBrush(Qt::NoBrush);
const int rows = qRound(floor(m_glyphs.size() / COLUMNS_COUNT)) + 1;
const auto maxH = qMin(rows * cellHeight, (double)horizontalScrollBar()->maximum());
double x = cellHeight;
for (int c = 1; c < COLUMNS_COUNT; ++c) {
p.drawLine(QLineF(x, 0, x, maxH));
x += cellHeight;
}
double y = cellHeight;
for (int r = 1; r <= rows; ++r) {
p.drawLine(QLineF(0, y, horizontalScrollBar()->maximum() + viewport()->width(), y));
y += cellHeight;
}
}
void GlyphsView::mousePressEvent(QMouseEvent *e)
{
if (e->button() & Qt::LeftButton) {
m_mousePressPos = e->pos();
m_origOffset = QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
}
}
void GlyphsView::mouseMoveEvent(QMouseEvent *e)
{
if (m_mousePressPos.isNull()) {
return;
}
const auto diff = m_mousePressPos - e->pos();
horizontalScrollBar()->setValue(m_origOffset.x() + diff.x());
verticalScrollBar()->setValue(m_origOffset.y() + diff.y());
}
void GlyphsView::mouseReleaseEvent(QMouseEvent *)
{
m_mousePressPos = QPoint();
m_origOffset = QPoint();
}
void GlyphsView::wheelEvent(QWheelEvent *e)
{
e->accept();
if (e->delta() > 0) {
m_scale += 0.01;
} else {
m_scale -= 0.01;
}
m_scale = qBound(0.03, m_scale, 1.0);
updateScrollBars();
viewport()->update();
}
void GlyphsView::resizeEvent(QResizeEvent *e)
{
QAbstractScrollArea::resizeEvent(e);
updateScrollBars();
}
void GlyphsView::updateScrollBars()
{
const double cellHeight = m_fontInfo.height * m_scale;
const int rows = qRound(floor(m_glyphs.size() / COLUMNS_COUNT)) + 1;
const auto w = COLUMNS_COUNT * cellHeight - viewport()->width();
const auto h = rows * cellHeight - viewport()->height();
horizontalScrollBar()->setMinimum(0);
verticalScrollBar()->setMinimum(0);
horizontalScrollBar()->setMaximum(qMax(0, qRound(w)));
verticalScrollBar()->setMaximum(qMax(0, qRound(h)));
}