Move the dark canvas into PaletteGraphicsView and test it directly

The inverted painting, the rubber band replay and the changed()
receiver lived in DiagramView, which the unit tests cannot link, so the
update-flag regression was only covered through a stand-in view. They
now live in PaletteGraphicsView, a QGraphicsView subclass with no
other dependency, and DiagramView derives from it. The view tells a
subclass through paintingInverted(bool) when it renders for an
inverted display; DiagramView forwards that to the diagram. The grid
dot rule moves out of Diagram::drawBackground into
QET::Palette::gridDotColor().

tst_qetpalette now links the real class: gridDotColorSoftensInvertedDots,
paletteViewFollowsThePalette (light sheet, dark sheet at text contrast
with a red box still red and the paintingInverted calls in order, back
to light), paletteViewKeepsSceneUpdatesFlowing (three whole-scene
updates and a selection each repaint, scene set after construction),
paletteViewDrawsTheRubberBand.
This commit is contained in:
Jeff Patterson
2026-09-19 14:28:23 -05:00
parent b8c9e670c4
commit eaf15faaa3
11 changed files with 413 additions and 137 deletions
+7 -88
View File
@@ -29,7 +29,6 @@
#include "qetgraphicsitem/conductortextitem.h"
#include "qetgraphicsitem/independenttextitem.h"
#include "qeticons.h"
#include "qetpalette.h"
#include "titleblock/integrationmovetemplateshandler.h"
#include "ui/diagrampropertiesdialog.h"
#include "ui/multipastedialog.h"
@@ -44,9 +43,6 @@
#include <QDropEvent>
#include <QPainter>
#include <QPointer>
#include <QStyleHintReturnMask>
#include <QStyleOptionRubberBand>
#include <QtMath>
/**
Constructeur
@@ -54,7 +50,7 @@
@param parent Le QWidget parent de cette vue de schema
*/
DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
QGraphicsView (parent),
PaletteGraphicsView (parent),
m_diagram (diagram)
{
grabGesture(Qt::PinchGesture);
@@ -108,17 +104,6 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
connect(m_diagram, &Diagram::showDiagram, this, &DiagramView::showDiagram);
connect(m_diagram, &QGraphicsScene::sceneRectChanged, this, &DiagramView::adjustSceneRect);
/* On a dark palette this view paints the scene into an image (see
* paintInverted). QGraphicsView delivers scene updates straight to
* its viewport when nobody listens to QGraphicsScene::changed(),
* and in that mode the scene clears its "update everything" flag
* only when the items are painted straight onto the viewport,
* which never happens here: from the second update on, grid and
* background toggles and even a selection would wait for an
* unrelated repaint. With a receiver connected the scene sends its
* updates through the signal, and clears the flag before it
* emits. Any receiver does; this one has nothing to do. */
connect(m_diagram, &QGraphicsScene::changed, this, [](const QList<QRectF> &) {});
connect(&(m_diagram -> border_and_titleblock), &BorderTitleBlock::informationChanged, this, &DiagramView::updateWindowTitle);
connect(diagram, &Diagram::findElementRequired, this, &DiagramView::findElementRequired);
@@ -1099,76 +1084,13 @@ bool DiagramView::event(QEvent *e) {
}
/**
@brief DiagramView::canvasIsInverted
@return true when the folio must be drawn with its lightness inverted,
i.e. when the application palette is dark. The document keeps its own
colors; only the screen rendering changes, so printing and exporting
stay black on white.
@brief DiagramView::paintingInverted
Reimplemented from PaletteGraphicsView: tell the diagram it is being
drawn for an inverted display, so it softens its grid.
*/
bool DiagramView::canvasIsInverted() const
void DiagramView::paintingInverted(bool inverted)
{
return QET::Palette::isDark(qApp->palette());
}
/**
@brief DiagramView::paintInverted
Render \a area of the viewport into an off-screen image, invert the
lightness of that image and blit it to the viewport. Inverting the
finished rendering turns the white sheet black and the black ink white
in one pass, and keeps the hue of colored conductors and elements.
@param area the part of the viewport to repaint, in viewport coordinates
*/
void DiagramView::paintInverted(const QRect &area)
{
const QRect rect = area.intersected(viewport()->rect());
if (rect.isEmpty())
return;
const qreal ratio = viewport()->devicePixelRatioF();
QImage buffer(qCeil(rect.width() * ratio), qCeil(rect.height() * ratio),
QImage::Format_RGB32);
buffer.setDevicePixelRatio(ratio);
QPainter buffer_painter(&buffer);
buffer_painter.setRenderHints(renderHints());
m_diagram->setInvertedLightness(true);
render(&buffer_painter, QRectF(QPointF(0, 0), QSizeF(rect.size())),
rect, Qt::IgnoreAspectRatio);
m_diagram->setInvertedLightness(false);
buffer_painter.end();
QET::Palette::invertLightness(buffer, palette().color(QPalette::Base),
palette().color(QPalette::Text));
QPainter painter(viewport());
painter.drawImage(rect.topLeft(), buffer);
drawRubberBand(painter);
}
/**
@brief DiagramView::drawRubberBand
Draw the selection rubber band the way QGraphicsView::paintEvent does.
Rendering the view into an off-screen image skips it, so it is drawn
here instead, after the inversion, and keeps the palette colors.
@param painter a painter on the viewport
*/
void DiagramView::drawRubberBand(QPainter &painter)
{
const QRect band = rubberBandRect();
if (band.isNull())
return;
QStyleOptionRubberBand option;
option.initFrom(viewport());
option.rect = band;
option.shape = QRubberBand::Rectangle;
QStyleHintReturnMask mask;
if (viewport()->style()->styleHint(QStyle::SH_RubberBand_Mask, &option,
viewport(), &mask))
painter.setClipRegion(mask.region, Qt::IntersectClip);
viewport()->style()->drawControl(QStyle::CE_RubberBand, &option,
&painter, viewport());
m_diagram->setInvertedLightness(inverted);
}
/**
@@ -1178,10 +1100,7 @@ void DiagramView::drawRubberBand(QPainter &painter)
*/
void DiagramView::paintEvent(QPaintEvent *event)
{
if (canvasIsInverted())
paintInverted(event->rect());
else
QGraphicsView::paintEvent(event);
PaletteGraphicsView::paintEvent(event);
if (m_free_rubberbanding && m_free_rubberband.count() >= 3)
{