Files
VX5_KRO_GearPump/scene/PicDateItem.cpp
T

213 lines
5.7 KiB
C++

#include "PicDateItem.h"
#include <QDebug>
#include <QRegExp>
#include <QPainter>
#include <QElapsedTimer>
#include "LogInfo.h"
#include "ItemCommon.h"
// 生成可能的最长时间字符串供尺寸计算使用(基于像素宽度)
static QString generateMaxDateTimeString(const DateItemModel &model, const QFont &font)
{
if (model.datetimePattern.isEmpty())
return QString();
QString s = model.datetimePattern;
QFontMetrics fm(font);
auto longestFromList = [&fm] (const QStringList &lst, const QString &fallback) {
int bestW = -1;
QString best;
for (const auto &v : lst) {
int w = fm.horizontalAdvance(v);
if (w > bestW) { bestW = w; best = v; }
}
return best.isEmpty() ? fallback : best;
};
int i = s.indexOf("yyyy");
if (i != -1) {
QString repl;
if (!model.yearsMap.isEmpty()) {
for (auto v : model.yearsMap.values()) if (v.length() > repl.length()) repl = v;
} else {
repl = QString::number(QDate::currentDate().year());
}
s.replace(i, 4, repl);
}
i = s.indexOf("YY");
if (i != -1) {
// 以像素宽度为准,'88' 通常足够宽
s.replace(i, 2, QString("88"));
}
i = s.indexOf("MM");
if (i != -1) {
s.replace(i, 2, longestFromList(model.monthsMap, QString("88")));
}
i = s.indexOf("dd");
if (i != -1) {
s.replace(i, 2, longestFromList(model.daysMap, QString("88")));
}
i = s.indexOf("HH");
if (i != -1) {
s.replace(i, 2, longestFromList(model.hoursMap, QString("88")));
}
QRegExp minutePattern("mm");
if (s.contains(minutePattern)) s.replace(minutePattern, QString("88"));
QRegExp secondPattern("ss");
if (s.contains(secondPattern)) s.replace(secondPattern, QString("88"));
i = s.indexOf("w");
if (i != -1) {
s.replace(i, 1, longestFromList(model.weeksMap, QString("888")));
}
QRegExp weekNumberPattern("c");
if (s.contains(weekNumberPattern)) s.replace(weekNumberPattern, QString("88"));
return s;
}
PicDateItem::PicDateItem(QGraphicsItem *parent, QGraphicsScene *scene, const SourceType type)
:PicTextItem(parent, scene, type)
{
m_timer.setInterval(20);
connect(&m_timer, &QTimer::timeout, [this](){
updateDatetimeStr();
});
// m_timer.start();
}
QVariant PicDateItem::source()
{
return m_model.datetimePattern;
}
void PicDateItem::setSource(QVariant var)
{
m_model.datetimePattern = var.toString();
if(m_model.datetimePattern.isEmpty())
return;
m_currDateTimeStr = ItemUtils::generateTxtFromDateItemModel(m_model, QDateTime::currentDateTime());
applyModify();
}
void PicDateItem::setModel(DateItemModel model)
{
m_model = std::move(model);
// 计时:测量生成最长字符串和字体度量两段耗时
QElapsedTimer t1;
t1.start();
m_maxDateTimeStr = generateMaxDateTimeString(m_model, font());
qint64 genUs = t1.nsecsElapsed() / 1000; // microseconds
QElapsedTimer t2;
t2.start();
if (m_maxDateTimeStr.isEmpty()) {
m_maxSize = QSize();
} else {
QFontMetrics fm(font());
int w = fm.horizontalAdvance(m_maxDateTimeStr);
int h = fm.height();
m_maxSize = QSize(w, h);
}
qint64 fmUs = t2.nsecsElapsed() / 1000; // microseconds
qDebug() << "PicDateItem::setModel timing(us): generate=" << genUs << ", fm=" << fmUs << ", total=" << (genUs + fmUs);
setSource(m_model.datetimePattern);
}
const DateItemModel& PicDateItem::model() const
{
return m_model;
}
bool PicDateItem::updateDatetimeStr()
{
if (m_model.datetimePattern.isEmpty())
return false;
if(m_currDateTimeStr.isEmpty()) {
m_currDateTimeStr = ItemUtils::generateTxtFromDateItemModel(m_model, QDateTime::currentDateTime());
applyModify();
return true;
}
auto now = QDateTime::currentDateTime();
auto str = ItemUtils::generateTxtFromDateItemModel(m_model, now);
if(str == m_currDateTimeStr) {
return false;
}
m_currDateTimeStr = str;
applyModify();
return true;
}
void PicDateItem::setCustomAttrs(const QXmlStreamAttributes &attrs)
{
// 结构类似这样
// weeksMap = "MON<br>TUR<br>WED<br>TUE<br>THU<br>FRI<br>SAT<br>SUN"
// yearsMap = "2023<subbr>2023年<br>2024<subbr>2024年<br>2025<subbr>2025年"
auto m = DateItemModel();
DateItemModel::loadFromXml(m, attrs);
setModel(std::move(m));
}
void PicDateItem::saveCustomAttrs(QXmlStreamAttributes &attrs)
{
DateItemModel::saveToXml(m_model, attrs);
}
QImage PicDateItem::itemImage()
{
if(m_model.datetimePattern.isEmpty())
return QImage();
auto currImg = strToImage(m_currDateTimeStr);
if (m_maxSize.isEmpty())
return currImg;
int width = qMax(currImg.width(), m_maxSize.width());
int height = qMax(currImg.height(), m_maxSize.height());
QImage img(width, height, QImage::Format_ARGB32);
img.fill(QColor(0,0,0,0).rgba());
QPainter painter(&img);
int y = (height - currImg.height()) / 2;
painter.drawImage(0, y, currImg);
painter.end();
return img;
}
QRectF PicDateItem::boundingRect() const
{
// 优先使用已经应用变换后的 m_itemImage(与 PicTextItem 保持一致)
if (!m_itemImage.isNull()) {
return QRectF(0, 0, m_itemImage.width(), m_itemImage.height());
}
// 否则基于缓存的最大像素尺寸和粗体倍数估算
int w = m_maxSize.width();
int h = m_maxSize.height();
if (w <= 0 || h <= 0)
return QGraphicsTextItem::boundingRect();
qreal bw = qreal(w) * qMax(1, m_boldMultiple);
return QRectF(0, 0, bw, qreal(h));
}