Skip to content

Commit

Permalink
subtitlewidget: fixes high cpu usage
Browse files Browse the repository at this point in the history
The previous implementation of SubtitleWidget had very high CPU usage
for unknown reasons. Turns out that an infinite loop was created by
overriding paintEvent and then doing cursor operations in there.
Basically new updates were being created inside of paintEvent which
would baloon over until subtitleWidget was hidden or the event queue was
too large.

This fixes the problem by completely ignoring the StackOverflow solution
and instead doing things the "dumb" way, i.e. having one QTextEdit with
a stroke in the background, and another QTextEdit overlayed on top of
that QTextEdit as the foreground. This achieves a similar effect without
the high CPU usage or having to override paintEvent.

This new widget is called at StrokeLabel and both ProgessSlider and
SubtitleWidget depend on it.
  • Loading branch information
ripose-jp committed Sep 26, 2021
1 parent 9f37ffa commit c16b357
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 232 deletions.
15 changes: 7 additions & 8 deletions src/gui/widgets/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@ target_link_libraries(
)

add_library(
sliderjumpstyle
sliderjumpstyle.cpp
strokelabel
strokelabel.cpp
)
target_link_libraries(
sliderjumpstyle
strokelabel
Qt5::Widgets
)

add_library(
progressslider
progressslider.cpp
sliderjumpstyle
sliderjumpstyle.cpp
)
target_link_libraries(
progressslider
sliderjumpstyle
Qt5::Widgets
Qt5::Core
)

add_library(
Expand All @@ -42,4 +41,4 @@ add_library(
target_link_libraries(
scrolldoublespinbox
Qt5::Widgets
)
)
234 changes: 234 additions & 0 deletions src/gui/widgets/common/strokelabel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2021 Ripose
//
// This file is part of Memento.
//
// Memento is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2 of the License.
//
// Memento is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Memento. If not, see <https://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////

#include "strokelabel.h"

#include <QAbstractTextDocumentLayout>
#include <QTextEdit>

/* Begin Constructor/Destructor */

#define TRANSPARENT_COLOR QColor("#00000000")

StrokeLabel::StrokeLabel(QWidget *parent)
: QWidget(parent),
m_backgroundText(new QTextEdit(this)),
m_foregroundText(new QTextEdit(this)),
m_textColor(palette().text().color()),
m_strokeColor(palette().window().color()),
m_strokeSize(4.0),
m_backgroundColor(TRANSPARENT_COLOR)
{
initTextEdit(m_backgroundText);

initTextEdit(m_foregroundText);
m_foregroundText->raise();

setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFocusPolicy(Qt::FocusPolicy::NoFocus);
fitToContents();
updateColors();
}

void StrokeLabel::initTextEdit(QTextEdit *te)
{
te->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
te->setFocusPolicy(Qt::FocusPolicy::NoFocus);
te->setAcceptDrops(false);
te->setFrameShape(QFrame::Shape::NoFrame);
te->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
te->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
te->setLineWrapMode(QTextEdit::NoWrap);
te->setReadOnly(true);
te->setAcceptRichText(false);
te->setTextInteractionFlags(Qt::NoTextInteraction);
te->setCursor(Qt::ArrowCursor);
}

void StrokeLabel::updateColors()
{
/* Set the text and background color */
QString stylesheetFormat =
"QTextEdit {"
"color: rgba(%1, %2, %3, %4);"
"background: rgba(0, 0, 0, 0);"
"}";
m_foregroundText->setStyleSheet(
stylesheetFormat.arg(QString::number(m_textColor.red()))
.arg(QString::number(m_textColor.green()))
.arg(QString::number(m_textColor.blue()))
.arg(QString::number(m_textColor.alpha()))
);

stylesheetFormat =
"QTextEdit {"
"color: rgba(%1, %2, %3, %4);"
"background: rgba(%5, %6, %7, %8);"
"}";
m_backgroundText->setStyleSheet(
stylesheetFormat.arg(QString::number(m_textColor.red()))
.arg(QString::number(m_textColor.green()))
.arg(QString::number(m_textColor.blue()))
.arg(QString::number(m_textColor.alpha()))
.arg(QString::number(m_backgroundColor.red()))
.arg(QString::number(m_backgroundColor.green()))
.arg(QString::number(m_backgroundColor.blue()))
.arg(QString::number(m_backgroundColor.alpha()))
);

setText(m_foregroundText->toPlainText());
}


void StrokeLabel::fitToContents()
{
m_backgroundText->updateGeometry();
int width = m_backgroundText->document()->idealWidth() + 4;
int height = m_backgroundText->document()->size().toSize().height();
setSize(width, height);
}

#undef TRANSPARENT_COLOR

/* End Constructor/Destructor */
/* Begin Color Setters */

void StrokeLabel::setTextColor(const QColor &color)
{
m_textColor = color;
updateColors();
}

void StrokeLabel::setStrokeColor(const QColor &color)
{
m_strokeColor = color;
updateColors();
}

void StrokeLabel::setStrokeSize(double size)
{
m_strokeSize = size;
updateColors();
}

void StrokeLabel::setBackgroundColor(const QColor &color)
{
m_backgroundColor = color;
updateColors();
}

/* End Color Setters */
/* Begin Font Methods */

QFont StrokeLabel::textFont() const
{
return m_foregroundText->font();
}

void StrokeLabel::setTextFont(const QFont &f)
{
m_foregroundText->setFont(f);
m_backgroundText->setFont(f);
fitToContents();
}

/* End Font Methods */
/* Begin Text Methods */

void StrokeLabel::setText(const QString &text)
{
clearText();
QStringList subList = text.split('\n');
for (const QString &text : subList)
{
if (text.isEmpty())
continue;

m_backgroundText->append(text);
m_backgroundText->setAlignment(Qt::AlignHCenter);

m_foregroundText->append(text);
m_foregroundText->setAlignment(Qt::AlignHCenter);
}

/* Add the stroke */
QTextCharFormat format;
format.setTextOutline(
QPen(
m_strokeColor,
m_strokeSize,
Qt::SolidLine,
Qt::RoundCap,
Qt::RoundJoin
)
);
QTextCursor cursor(m_backgroundText->document());
cursor.select(QTextCursor::Document);
cursor.mergeCharFormat(format);

fitToContents();
}


QString StrokeLabel::getText() const
{
return m_foregroundText->toPlainText();
}

void StrokeLabel::clearText()
{
m_backgroundText->clear();
m_foregroundText->clear();
setSize(0, 0);
}

void StrokeLabel::selectText(int start, int length)
{
QTextCursor q = m_foregroundText->textCursor();
q.setPosition(start);
q.setPosition(start + length, QTextCursor::KeepAnchor);
m_foregroundText->setTextCursor(q);
}

void StrokeLabel::deselectText()
{
QTextCursor q = m_foregroundText->textCursor();
q.clearSelection();
m_foregroundText->setTextCursor(q);
}

/* End Text Methods */
/* Begin Helper Methods */

void StrokeLabel::setSize(int w, int h)
{
m_backgroundText->setFixedSize(w, h);
m_foregroundText->setFixedSize(w, h);
setFixedSize(w, h);
}

int StrokeLabel::getPosition(const QPoint &pos) const
{
return m_foregroundText->document()->documentLayout()->hitTest(
pos, Qt::ExactHit
);
}

/* End Helper Methods */

0 comments on commit c16b357

Please sign in to comment.