mirror of
https://github.com/Swordfish90/cool-retro-term.git
synced 2025-02-16 01:48:38 +00:00
250 lines
7.2 KiB
C++
250 lines
7.2 KiB
C++
/******************************************************************************
|
|
* Copyright (c) 2012 Jørgen Lind
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "mono_text.h"
|
|
|
|
#include <QtQuick/private/qsgadaptationlayer_p.h>
|
|
#include <QtQuick/private/qsgrenderer_p.h>
|
|
#include <QtQuick/private/qquickitem_p.h>
|
|
#include <QtQuick/private/qquicktextnode_p.h>
|
|
#include <QtGui/QTextLayout>
|
|
|
|
class MonoSGNode : public QSGTransformNode
|
|
{
|
|
public:
|
|
MonoSGNode(QQuickItem *owner)
|
|
: m_owner(owner)
|
|
{
|
|
}
|
|
|
|
void deleteContent()
|
|
{
|
|
QSGNode *subnode = firstChild();
|
|
while (subnode) {
|
|
// We can't delete the node now as it might be in the preprocess list
|
|
// It will be deleted in the next preprocess
|
|
m_nodes_to_delete.append(subnode);
|
|
subnode = subnode->nextSibling();
|
|
}
|
|
removeAllChildNodes();
|
|
}
|
|
|
|
void preprocess()
|
|
{
|
|
while (m_nodes_to_delete.count())
|
|
delete m_nodes_to_delete.takeLast();
|
|
}
|
|
|
|
void setLatinText(const QString &text, const QFont &font, const QColor &color) {
|
|
QRawFont raw_font = QRawFont::fromFont(font, QFontDatabase::Latin);
|
|
|
|
if (raw_font != m_raw_font) {
|
|
m_raw_font = raw_font;
|
|
m_positions.clear();
|
|
}
|
|
|
|
if (m_positions.size() < text.size()) {
|
|
qreal x_pos = 0;
|
|
qreal max_char_width = raw_font.averageCharWidth();
|
|
qreal ascent = raw_font.ascent();
|
|
if (m_positions.size())
|
|
x_pos = m_positions.last().x() + max_char_width;
|
|
int to_add = text.size() - m_positions.size();
|
|
for (int i = 0; i < to_add; i++) {
|
|
m_positions << QPointF(x_pos, ascent);
|
|
x_pos += max_char_width;
|
|
}
|
|
}
|
|
|
|
deleteContent();
|
|
QSGRenderContext *sgr = QQuickItemPrivate::get(m_owner)->sceneGraphRenderContext();
|
|
QSGGlyphNode *node = sgr->sceneGraphContext()->createGlyphNode(sgr);
|
|
node->setOwnerElement(m_owner);
|
|
node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern);
|
|
node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern);
|
|
node->setStyle(QQuickText::Normal);
|
|
|
|
node->setColor(color);
|
|
QGlyphRun glyphrun;
|
|
glyphrun.setRawFont(raw_font);
|
|
glyphrun.setGlyphIndexes(raw_font.glyphIndexesForString(text));
|
|
|
|
glyphrun.setPositions(m_positions);
|
|
node->setGlyphs(QPointF(0, raw_font.ascent()), glyphrun);
|
|
node->update();
|
|
appendChildNode(node);
|
|
}
|
|
|
|
void setUnicodeText(const QString &text, const QFont &font, const QColor &color)
|
|
{
|
|
deleteContent();
|
|
QRawFont raw_font = QRawFont::fromFont(font, QFontDatabase::Latin);
|
|
qreal line_width = raw_font.averageCharWidth() * text.size();
|
|
QSGRenderContext *sgr = QQuickItemPrivate::get(m_owner)->sceneGraphRenderContext();
|
|
QTextLayout layout(text,font);
|
|
layout.beginLayout();
|
|
QTextLine line = layout.createLine();
|
|
line.setLineWidth(line_width);
|
|
//Q_ASSERT(!layout.createLine().isValid());
|
|
layout.endLayout();
|
|
QList<QGlyphRun> glyphRuns = line.glyphRuns();
|
|
qreal xpos = 0;
|
|
for (int i = 0; i < glyphRuns.size(); i++) {
|
|
QSGGlyphNode *node = sgr->sceneGraphContext()->createGlyphNode(sgr);
|
|
node->setOwnerElement(m_owner);
|
|
node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern);
|
|
node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern);
|
|
node->setGlyphs(QPointF(xpos, raw_font.ascent()), glyphRuns.at(i));
|
|
node->setStyle(QQuickText::Normal);
|
|
node->setColor(color);
|
|
xpos += raw_font.averageCharWidth() * glyphRuns.at(i).positions().size();
|
|
node->update();
|
|
appendChildNode(node);
|
|
}
|
|
}
|
|
private:
|
|
QQuickItem *m_owner;
|
|
QVector<QPointF> m_positions;
|
|
QLinkedList<QSGNode *> m_nodes_to_delete;
|
|
QRawFont m_raw_font;
|
|
};
|
|
|
|
MonoText::MonoText(QQuickItem *parent)
|
|
: QQuickItem(parent)
|
|
, m_color_changed(false)
|
|
, m_latin(true)
|
|
, m_old_latin(true)
|
|
{
|
|
setFlag(ItemHasContents, true);
|
|
}
|
|
|
|
MonoText::~MonoText()
|
|
{
|
|
|
|
}
|
|
|
|
QString MonoText::text() const
|
|
{
|
|
return m_text;
|
|
}
|
|
|
|
void MonoText::setText(const QString &text)
|
|
{
|
|
if (m_text != text) {
|
|
m_text = text;
|
|
emit textChanged();
|
|
polish();
|
|
}
|
|
}
|
|
|
|
QFont MonoText::font() const
|
|
{
|
|
return m_font;
|
|
}
|
|
|
|
void MonoText::setFont(const QFont &font)
|
|
{
|
|
if (font != m_font) {
|
|
m_font = font;
|
|
emit fontChanged();
|
|
polish();
|
|
}
|
|
}
|
|
|
|
QColor MonoText::color() const
|
|
{
|
|
return m_color;
|
|
}
|
|
|
|
void MonoText::setColor(const QColor &color)
|
|
{
|
|
if (m_color != color) {
|
|
m_color = color;
|
|
emit colorChanged();
|
|
update();
|
|
}
|
|
}
|
|
|
|
qreal MonoText::paintedWidth() const
|
|
{
|
|
return implicitWidth();
|
|
}
|
|
|
|
qreal MonoText::paintedHeight() const
|
|
{
|
|
return implicitHeight();
|
|
}
|
|
|
|
bool MonoText::latin() const
|
|
{
|
|
return m_latin;
|
|
}
|
|
|
|
void MonoText::setLatin(bool latin)
|
|
{
|
|
if (latin == m_latin)
|
|
return;
|
|
|
|
m_latin = latin;
|
|
emit latinChanged();
|
|
}
|
|
|
|
QSGNode *MonoText::updatePaintNode(QSGNode *old, UpdatePaintNodeData *)
|
|
{
|
|
if (m_text.size() == 0 || m_text.trimmed().size() == 0) {
|
|
delete old;
|
|
return 0;
|
|
}
|
|
MonoSGNode *node = static_cast<MonoSGNode *>(old);
|
|
if (!node) {
|
|
node = new MonoSGNode(this);
|
|
}
|
|
|
|
if (m_latin) {
|
|
node->setLatinText(m_text, m_font, m_color);
|
|
} else {
|
|
node->setUnicodeText(m_text, m_font, m_color);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
void MonoText::updatePolish()
|
|
{
|
|
QRawFont raw_font = QRawFont::fromFont(m_font, QFontDatabase::Latin);
|
|
|
|
qreal height = raw_font.descent() + raw_font.ascent() + raw_font.lineThickness();
|
|
qreal width = raw_font.averageCharWidth() * m_text.size();
|
|
|
|
bool emit_text_width_changed = width != implicitWidth();
|
|
bool emit_text_height_changed = height != implicitHeight();
|
|
setImplicitSize(width, height);
|
|
|
|
if (emit_text_width_changed)
|
|
emit paintedWidthChanged();
|
|
if (emit_text_height_changed)
|
|
emit paintedHeightChanged();
|
|
|
|
update();
|
|
}
|