/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "arthurwidgets.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_CONFIG(opengl) #include #include #endif extern QPixmap cached(const QString &img); ArthurFrame::ArthurFrame(QWidget *parent) : QWidget(parent) , m_prefer_image(false) { #if QT_CONFIG(opengl) m_glWindow = nullptr; m_glWidget = nullptr; m_use_opengl = false; #endif m_document = nullptr; m_show_doc = false; m_tile = QPixmap(128, 128); m_tile.fill(Qt::white); QPainter pt(&m_tile); QColor color(230, 230, 230); pt.fillRect(0, 0, 64, 64, color); pt.fillRect(64, 64, 64, 64, color); pt.end(); // QPalette pal = palette(); // pal.setBrush(backgroundRole(), m_tile); // setPalette(pal); } #if QT_CONFIG(opengl) void ArthurFrame::enableOpenGL(bool use_opengl) { if (m_use_opengl == use_opengl) return; m_use_opengl = use_opengl; if (!m_glWindow && use_opengl) { createGlWindow(); QApplication::postEvent(this, new QResizeEvent(size(), size())); } if (use_opengl) { m_glWidget->show(); } else { if (m_glWidget) m_glWidget->hide(); } update(); } void ArthurFrame::createGlWindow() { Q_ASSERT(m_use_opengl); m_glWindow = new QOpenGLWindow(); QSurfaceFormat f = QSurfaceFormat::defaultFormat(); f.setSamples(4); f.setAlphaBufferSize(8); f.setStencilBufferSize(8); m_glWindow->setFormat(f); m_glWindow->setFlags(Qt::WindowTransparentForInput); m_glWindow->resize(width() - 1, height() - 1); m_glWindow->create(); m_glWidget = QWidget::createWindowContainer(m_glWindow, this); } #endif void ArthurFrame::paintEvent(QPaintEvent *e) { static QImage *static_image = nullptr; QPainter painter; if (preferImage() #if QT_CONFIG(opengl) && !m_use_opengl #endif ) { if (!static_image || static_image->size() != size()) { delete static_image; static_image = new QImage(size(), QImage::Format_RGB32); } painter.begin(static_image); int o = 10; QBrush bg = palette().brush(QPalette::Window); painter.fillRect(0, 0, o, o, bg); painter.fillRect(width() - o, 0, o, o, bg); painter.fillRect(0, height() - o, o, o, bg); painter.fillRect(width() - o, height() - o, o, o, bg); } else { #if QT_CONFIG(opengl) if (m_use_opengl && m_glWindow->isValid()) { m_glWindow->makeCurrent(); painter.begin(m_glWindow); painter.fillRect(QRectF(0, 0, m_glWindow->width(), m_glWindow->height()), palette().color(backgroundRole())); } else { painter.begin(this); } #else painter.begin(this); #endif } painter.setClipRect(e->rect()); painter.setRenderHint(QPainter::Antialiasing); QPainterPath clipPath; QRect r = rect(); qreal left = r.x() + 1; qreal top = r.y() + 1; qreal right = r.right(); qreal bottom = r.bottom(); qreal radius2 = 8 * 2; clipPath.moveTo(right - radius2, top); clipPath.arcTo(right - radius2, top, radius2, radius2, 90, -90); clipPath.arcTo(right - radius2, bottom - radius2, radius2, radius2, 0, -90); clipPath.arcTo(left, bottom - radius2, radius2, radius2, 270, -90); clipPath.arcTo(left, top, radius2, radius2, 180, -90); clipPath.closeSubpath(); painter.save(); painter.setClipPath(clipPath, Qt::IntersectClip); painter.drawTiledPixmap(rect(), m_tile); // client painting paint(&painter); painter.restore(); painter.save(); if (m_show_doc) paintDescription(&painter); painter.restore(); int level = 180; painter.setPen(QPen(QColor(level, level, level), 2)); painter.setBrush(Qt::NoBrush); painter.drawPath(clipPath); if (preferImage() #if QT_CONFIG(opengl) && !m_use_opengl #endif ) { painter.end(); painter.begin(this); painter.drawImage(e->rect(), *static_image, e->rect()); } #if QT_CONFIG(opengl) if (m_use_opengl) m_glWindow->update(); #endif } void ArthurFrame::resizeEvent(QResizeEvent *e) { #if QT_CONFIG(opengl) if (m_glWidget) m_glWidget->setGeometry(0, 0, e->size().width()-1, e->size().height()-1); #endif QWidget::resizeEvent(e); } void ArthurFrame::setDescriptionEnabled(bool enabled) { if (m_show_doc != enabled) { m_show_doc = enabled; emit descriptionEnabledChanged(m_show_doc); update(); } } void ArthurFrame::loadDescription(const QString &fileName) { QFile textFile(fileName); QString text; if (!textFile.open(QFile::ReadOnly)) text = QString("Unable to load resource file: '%1'").arg(fileName); else text = textFile.readAll(); setDescription(text); } void ArthurFrame::setDescription(const QString &text) { m_document = new QTextDocument(this); m_document->setHtml(text); } void ArthurFrame::paintDescription(QPainter *painter) { if (!m_document) return; int pageWidth = qMax(width() - 100, 100); int pageHeight = qMax(height() - 100, 100); if (pageWidth != m_document->pageSize().width()) { m_document->setPageSize(QSize(pageWidth, pageHeight)); } QRect textRect(width() / 2 - pageWidth / 2, height() / 2 - pageHeight / 2, pageWidth, pageHeight); int pad = 10; QRect clearRect = textRect.adjusted(-pad, -pad, pad, pad); painter->setPen(Qt::NoPen); painter->setBrush(QColor(0, 0, 0, 63)); int shade = 10; painter->drawRect(clearRect.x() + clearRect.width() + 1, clearRect.y() + shade, shade, clearRect.height() + 1); painter->drawRect(clearRect.x() + shade, clearRect.y() + clearRect.height() + 1, clearRect.width() - shade + 1, shade); painter->setRenderHint(QPainter::Antialiasing, false); painter->setBrush(QColor(255, 255, 255, 220)); painter->setPen(Qt::black); painter->drawRect(clearRect); painter->setClipRegion(textRect, Qt::IntersectClip); painter->translate(textRect.topLeft()); QAbstractTextDocumentLayout::PaintContext ctx; QLinearGradient g(0, 0, 0, textRect.height()); g.setColorAt(0, Qt::black); g.setColorAt(0.9, Qt::black); g.setColorAt(1, Qt::transparent); QPalette pal = palette(); pal.setBrush(QPalette::Text, g); ctx.palette = pal; ctx.clip = QRect(0, 0, textRect.width(), textRect.height()); m_document->documentLayout()->draw(painter, ctx); } void ArthurFrame::loadSourceFile(const QString &sourceFile) { m_sourceFileName = sourceFile; } void ArthurFrame::showSource() { // Check for existing source if (findChild()) return; QString contents; if (m_sourceFileName.isEmpty()) { contents = tr("No source for widget: '%1'").arg(objectName()); } else { QFile f(m_sourceFileName); if (!f.open(QFile::ReadOnly)) contents = tr("Could not open file: '%1'").arg(m_sourceFileName); else contents = f.readAll(); } contents.replace(QLatin1Char('&'), QStringLiteral("&")); contents.replace(QLatin1Char('<'), QStringLiteral("<")); contents.replace(QLatin1Char('>'), QStringLiteral(">")); static const QString keywords[] = { QStringLiteral("for "), QStringLiteral("if "), QStringLiteral("switch "), QStringLiteral(" int "), QStringLiteral("#include "), QStringLiteral("const"), QStringLiteral("void "), QStringLiteral("uint "), QStringLiteral("case "), QStringLiteral("double "), QStringLiteral("#define "), QStringLiteral("static"), QStringLiteral("new"), QStringLiteral("this") }; for (const QString &keyword : keywords) contents.replace(keyword, QLatin1String("") + keyword + QLatin1String("")); contents.replace(QStringLiteral("(int "), QStringLiteral("(int ")); static const QString ppKeywords[] = { QStringLiteral("#ifdef"), QStringLiteral("#ifndef"), QStringLiteral("#if"), QStringLiteral("#endif"), QStringLiteral("#else") }; for (const QString &keyword : ppKeywords) contents.replace(keyword, QLatin1String("") + keyword + QLatin1String("")); contents.replace(QRegularExpression("(\\d\\d?)"), QLatin1String("\\1")); QRegularExpression commentRe("(//.+?)\\n"); contents.replace(commentRe, QLatin1String("\\1\n")); QRegularExpression stringLiteralRe("(\".+?\")"); contents.replace(stringLiteralRe, QLatin1String("\\1")); const QString html = QStringLiteral("
") + contents + QStringLiteral("
"); QTextBrowser *sourceViewer = new QTextBrowser; sourceViewer->setWindowTitle(tr("Source: %1").arg(m_sourceFileName.midRef(5))); sourceViewer->setParent(this, Qt::Dialog); sourceViewer->setAttribute(Qt::WA_DeleteOnClose); sourceViewer->setLineWrapMode(QTextEdit::NoWrap); sourceViewer->setHtml(html); sourceViewer->resize(600, 600); sourceViewer->show(); }