Files
qelectrotech-source-mirror/sources/ElementsCollection/elementstreeview.cpp
T
Jeff Patterson 0395f90f75 Let the Collections and Projects panels follow the palette
Both panels forced a light palette on themselves (white rows, black
text, their own selection blue) so that element previews, which are
black line art drawn for the white sheet, would stay visible on a dark
desktop (bugtracker 335). On a dark palette the two docks were the
only white windows left.

The forced palettes are gone. Element previews are now kept as drawn,
on a transparent background, and adapted where they are shown:
ElementPreviewDelegate, installed on the collection tree, hands the
view a copy with its lightness inverted when the palette is dark
(QET::Palette::forPalette), so black ink becomes the palette's light
gray while colored icons such as folders stay as they are; the drag
pixmap is adapted the same way. A light palette shows the previews
untouched. This fixes bugtracker 335 on every dark desktop rather than
masking it with a white panel.

The preview cache stored the old white-sheet pictures; it records the
format now and drops a cache written before this change once. The
amber "show this directory" highlight sets black text so it reads on
both palettes. The Projects panel only shows icons from the icon
theme, which has a dark variant, so nothing else changes there.

tests/qttest/tst_qetpalette: the line-art rule tells ink from color;
inversion keeps hue and alpha; a preview reads at 3:1 on the Base
color of both palettes; in a tree on the dark palette the delegate
inverts a line-art icon and leaves a colored one alone.

Fixes #945.
2026-09-19 12:22:24 -05:00

240 lines
7.9 KiB
C++

/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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, either version 2 of the License, or
(at your option) any later version.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementstreeview.h"
#include "elementpreviewdelegate.h"
#include "../qetpalette.h"
#include "../factory/elementfactory.h"
#include "../qetgraphicsitem/element.h"
#include "../qeticons.h"
#include "elementcollectionitem.h"
#include "elementslocation.h"
#include "../qetproject.h"
#include "../diagram.h"
#include "xmlelementcollection.h"
#include "../NameList/nameslist.h"
#include <QPainter>
#include <QScopedPointer>
#include <QDrag>
#include <QStandardItemModel>
static int MAX_DND_PIXMAP_WIDTH = 500;
static int MAX_DND_PIXMAP_HEIGHT = 375;
/**
@brief ElementsTreeView::ElementsTreeView
@param parent
*/
ElementsTreeView::ElementsTreeView(QWidget *parent) :
QTreeView(parent)
{
// Rows follow the application palette. Element previews are black
// line art drawn for a white sheet; ElementPreviewDelegate adapts them
// to a dark palette, so this view no longer has to force a light one
// (bugtracker #335).
setItemDelegate(new ElementPreviewDelegate(this));
}
/**
@brief ElementsTreeView::startDrag
Reimplemented from QTreeView
@param supportedActions
*/
void ElementsTreeView::startDrag(Qt::DropActions supportedActions)
{
QModelIndex index = currentIndex();
if (!index.isValid()) {
QTreeView::startDrag(supportedActions);
return;
}
if (QStandardItemModel *qsim = static_cast<QStandardItemModel *>(model())) {
if (ElementCollectionItem *eci = static_cast<ElementCollectionItem *>(qsim->itemFromIndex(index))) {
ElementsLocation loc (eci->collectionPath());
if (loc.exist()) {
startElementDrag(loc);
return;
}
}
}
QTreeView::startDrag(supportedActions);
}
/**
@brief ElementsTreeView::startElementDrag
Build a QDrag according to the content of location
@param location : location to use for create the content of the QDrag
*/
void ElementsTreeView::startElementDrag(const ElementsLocation &location)
{
if (! location.exist()) return;
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
QDrag* drag = new QDrag(this);
#else
QScopedPointer<QDrag> drag(new QDrag(this));
#endif
QString location_str = location.toString();
QMimeData *mime_data = new QMimeData();
mime_data->setText(location_str);
if (location.isDirectory())
{
mime_data->setData("application/x-qet-category-uri",
location_str.toLatin1());
drag->setPixmap(QET::Icons::Folder.pixmap(22, 22));
}
else if (location.fileName().endsWith(".qetmak"))
{
mime_data->setData("application/x-qet-element-uri", location_str.toLatin1());
QPixmap macro_pixmap;
// --- MINI-RENDERER FÜR DAS MAKRO-VORSCHAUBILD ---
QFile file(location.fileSystemPath());
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QDomDocument macro_doc;
if (macro_doc.setContent(&file)) {
QDomElement root = macro_doc.documentElement();
if (root.tagName() == "qet_macro") {
// 1. Unsichtbares Dummy-Projekt erstellen
QScopedPointer<QETProject> dummy_project(new QETProject());
// 2. Bauteile in das Dummy-Projekt laden (wie beim echten Drop)
QDomElement collection_node = root.firstChildElement("collection");
if (!collection_node.isNull()) {
QDomNodeList elements = collection_node.elementsByTagName("element");
for (int i = 0; i < elements.count(); ++i) {
QDomElement elmt_node = elements.at(i).toElement();
QString path = elmt_node.attribute("path");
QDomElement definition = elmt_node.firstChildElement("definition");
if (!path.isEmpty() && !definition.isNull()) {
int last_slash = path.lastIndexOf('/');
QString dir_path = (last_slash != -1) ? path.left(last_slash) : "";
QString file_name = (last_slash != -1) ? path.mid(last_slash + 1) : path;
if (!dir_path.isEmpty()) {
QStringList parts = dir_path.split('/', Qt::SkipEmptyParts);
QString current_path = "";
for (const QString &part : parts) {
QString parent_path = current_path;
if (!current_path.isEmpty()) current_path += "/";
current_path += part;
if (current_path == "import") continue;
NamesList empty_names;
dummy_project->embeddedElementCollection()->createDir(parent_path, part, empty_names);
}
}
dummy_project->embeddedElementCollection()->addElementDefinition(dir_path, file_name, definition);
}
}
}
Diagram *dummy_diagram = dummy_project->addNewDiagram();
// 4. Makro auf dem unsichtbaren Blatt zeichnen
QDomElement diagram_content_node = root.firstChildElement("diagram_content");
QDomElement diagram_node = diagram_content_node.firstChildElement("diagram");
if (!diagram_node.isNull()) {
QDomNodeList instances = diagram_node.elementsByTagName("element");
for (int i = 0; i < instances.count(); ++i) {
QDomElement inst = instances.at(i).toElement();
QString type = inst.attribute("type");
if (type.startsWith("macro://")) {
inst.setAttribute("type", type.replace("macro://", "embed://"));
}
}
dummy_diagram->fromXml(diagram_node, QPointF(0, 0), false, nullptr);
dummy_diagram->clearSelection();
// 5. "Screenshot" (Pixmap) von den gezeichneten Elementen machen
QRectF scene_rect = dummy_diagram->itemsBoundingRect();
if (!scene_rect.isEmpty()) {
scene_rect.adjust(-5, -5, 5, 5); // Kleiner Rand
macro_pixmap = QPixmap(scene_rect.size().toSize());
macro_pixmap.fill(Qt::transparent); // Transparenter Hintergrund
QPainter painter(&macro_pixmap);
painter.setRenderHint(QPainter::Antialiasing);
dummy_diagram->render(&painter, macro_pixmap.rect(), scene_rect);
}
}
}
}
}
if (macro_pixmap.isNull()) {
macro_pixmap = QET::Icons::Project.pixmap(32, 32);
}
// Bild verkleinern, falls das Makro gigantisch groß ist
if (macro_pixmap.width() > MAX_DND_PIXMAP_WIDTH || macro_pixmap.height() > MAX_DND_PIXMAP_HEIGHT) {
macro_pixmap = macro_pixmap.scaled(MAX_DND_PIXMAP_WIDTH, MAX_DND_PIXMAP_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
drag->setPixmap(macro_pixmap);
// Bild zentriert an die Maus hängen
drag->setHotSpot(QPoint(macro_pixmap.width() / 2, macro_pixmap.height() / 2));
}
else if (location.isElement())
{
mime_data->setData("application/x-qet-element-uri",
location_str.toLatin1());
//Build the element for set the pixmap of the QDrag
int elmt_creation_state;
QScopedPointer<Element> temp_elmt(
ElementFactory::Instance()->createElement(
location,
nullptr,
&elmt_creation_state));
if (elmt_creation_state) { return; }
QPixmap elmt_pixmap(QET::Palette::forPalette(temp_elmt->pixmap(), palette()));
QPoint elmt_hotspot(temp_elmt->hotspot());
//Adjust the size of the pixmap if he is too big
QPoint elmt_pixmap_size(elmt_pixmap.width(),
elmt_pixmap.height());
if (elmt_pixmap.width()
> MAX_DND_PIXMAP_WIDTH
|| elmt_pixmap.height()
> MAX_DND_PIXMAP_HEIGHT)
{
elmt_pixmap = elmt_pixmap.scaled(
MAX_DND_PIXMAP_WIDTH,
MAX_DND_PIXMAP_HEIGHT,
Qt::KeepAspectRatio);
elmt_hotspot = QPoint(
elmt_hotspot.x() * elmt_pixmap.width() / elmt_pixmap_size.x(),
elmt_hotspot.y() * elmt_pixmap.height() / elmt_pixmap_size.y()
);
}
drag->setPixmap(elmt_pixmap);
drag->setHotSpot(elmt_hotspot);
}
drag->setMimeData(mime_data);
drag->exec(Qt::CopyAction);
}