修复关闭时候的错误

This commit is contained in:
2026-07-23 09:35:29 +08:00
parent c3e96d2f86
commit d1aac0e679
10 changed files with 207 additions and 71 deletions
-3
View File
@@ -88,7 +88,6 @@ namespace YSG {
RenderEditGuard::~RenderEditGuard() { RenderEditGuard::~RenderEditGuard() {
if(mData && mData->qPtr) mData->qPtr->markStateDirty(); if(mData && mData->qPtr) mData->qPtr->markStateDirty();
} }
void RenderAble::init(Plot* plot, QString layerName) { void RenderAble::init(Plot* plot, QString layerName) {
if(layerName.isEmpty()) { if(layerName.isEmpty()) {
layerName = plot->mDefaultLayerName; layerName = plot->mDefaultLayerName;
@@ -114,8 +113,6 @@ namespace YSG {
if(dPtr && dPtr->mRenderStateCache) ++dPtr->mRenderStateCache->version; if(dPtr && dPtr->mRenderStateCache) ++dPtr->mRenderStateCache->version;
if(mPlot) mPlot->markRenderStateDirty(); if(mPlot) mPlot->markRenderStateDirty();
} }
bool RenderAble::ok() const { bool RenderAble::ok() const {
return dPtr->mRenderStart && mPlot && !mPlot->mFirstResize && !mPlot->mFirstPrepareData; return dPtr->mRenderStart && mPlot && !mPlot->mFirstResize && !mPlot->mFirstPrepareData;
} }
+4
View File
@@ -65,6 +65,7 @@ protected:
virtual void mousePressEvent(QMouseEvent* event) {} virtual void mousePressEvent(QMouseEvent* event) {}
virtual void mouseMoveEvent(QMouseEvent* event) {} virtual void mouseMoveEvent(QMouseEvent* event) {}
virtual void mouseReleaseEvent(QMouseEvent* event) {} virtual void mouseReleaseEvent(QMouseEvent* event) {}
virtual void setHoverState(const QPoint& pos, bool active) {}
virtual void keyPressEvent(QKeyEvent* event) {} virtual void keyPressEvent(QKeyEvent* event) {}
virtual void keyReleaseEvent(QKeyEvent* event) {} virtual void keyReleaseEvent(QKeyEvent* event) {}
virtual void firstResizeEvent(QResizeEvent* event) {} virtual void firstResizeEvent(QResizeEvent* event) {}
@@ -153,6 +154,9 @@ struct RenderAble {
virtual void mouseReleaseEvent(QMouseEvent* event) { virtual void mouseReleaseEvent(QMouseEvent* event) {
dPtr->mouseReleaseEvent(event); dPtr->mouseReleaseEvent(event);
} }
virtual void setHoverState(const QPoint& pos, bool active) {
dPtr->setHoverState(pos, active);
}
virtual void keyPressEvent(QKeyEvent* event) { virtual void keyPressEvent(QKeyEvent* event) {
dPtr->keyPressEvent(event); dPtr->keyPressEvent(event);
} }
+88 -10
View File
@@ -1,7 +1,10 @@
#include "asio.hpp" #include "asio.hpp"
#include "Global.h" #include "Global.h"
#include <QApplication> #include <QApplication>
#include <atomic>
#include <algorithm> #include <algorithm>
#include <condition_variable>
#include <mutex>
#include <thread> #include <thread>
#include "Plot_p.h" #include "Plot_p.h"
@@ -11,15 +14,13 @@ namespace YSG {
std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type>> mWorkGuard; std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type>> mWorkGuard;
std::unique_ptr<asio::thread_pool> mCpuPool; std::unique_ptr<asio::thread_pool> mCpuPool;
std::thread::id mSchedulerThreadId; std::thread::id mSchedulerThreadId;
std::atomic_bool mIoActive{false};
std::atomic_bool mCpuJoined{false};
}; };
TimerThread::TimerThread() : d(std::make_unique<TimerThreadPrivate>()) { TimerThread::TimerThread() : d(std::make_unique<TimerThreadPrivate>()) {
connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() { connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() {
if (isRunning()) { shutdown();
d->mIoContext.stop();
if(d->mCpuPool) d->mCpuPool->stop();
wait();
}
delete this; delete this;
}); });
} }
@@ -31,6 +32,8 @@ namespace YSG {
d->mWorkGuard = std::make_unique<asio::executor_work_guard<asio::io_context::executor_type>>(d->mIoContext.get_executor()); d->mWorkGuard = std::make_unique<asio::executor_work_guard<asio::io_context::executor_type>>(d->mIoContext.get_executor());
unsigned cpuCount = std::max(1u, std::thread::hardware_concurrency() > 1 ? std::thread::hardware_concurrency() - 1 : 1u); unsigned cpuCount = std::max(1u, std::thread::hardware_concurrency() > 1 ? std::thread::hardware_concurrency() - 1 : 1u);
d->mCpuPool = std::make_unique<asio::thread_pool>(cpuCount); d->mCpuPool = std::make_unique<asio::thread_pool>(cpuCount);
d->mCpuJoined.store(false, std::memory_order_release);
d->mIoActive.store(true, std::memory_order_release);
for (auto &plot: mPlots) { for (auto &plot: mPlots) {
plot->d->mTimerThread = this; plot->d->mTimerThread = this;
plot->d->mRenderTimer = std::make_unique<asio::steady_timer>(d->mIoContext); plot->d->mRenderTimer = std::make_unique<asio::steady_timer>(d->mIoContext);
@@ -39,17 +42,15 @@ namespace YSG {
plot->requestRender(); plot->requestRender();
} }
d->mIoContext.run(); d->mIoContext.run();
d->mIoActive.store(false, std::memory_order_release);
for (auto &plot: mPlots) { for (auto &plot: mPlots) {
if(plot->d->mRenderTimer) { if(plot->d->mRenderTimer) {
plot->d->mRenderTimer->cancel(); plot->d->mRenderTimer->cancel();
plot->d->mRenderTimer.reset(); plot->d->mRenderTimer.reset();
} }
} }
if(d->mCpuPool) { joinCpuPool();
d->mCpuPool->stop(); d->mCpuPool.reset();
d->mCpuPool->join();
d->mCpuPool.reset();
}
d->mWorkGuard.reset(); d->mWorkGuard.reset();
} }
void TimerThread::post(std::function<void()> task) { void TimerThread::post(std::function<void()> task) {
@@ -68,6 +69,83 @@ namespace YSG {
asio::io_context& TimerThread::ioContext() { asio::io_context& TimerThread::ioContext() {
return d->mIoContext; return d->mIoContext;
} }
void TimerThread::removePlot(Plot* plot) {
postAndWait([this, plot]() {
removePlotOnScheduler(plot);
});
}
void TimerThread::shutdown() {
if(!isRunning()) {
shutdownOnScheduler();
stopSchedulerOnScheduler();
joinCpuPool();
d->mCpuPool.reset();
return;
}
if(isSchedulerThread()) {
shutdownOnScheduler();
stopSchedulerOnScheduler();
return;
}
postAndWait([this]() {
shutdownOnScheduler();
});
joinCpuPool();
postAndWait([this]() {
stopSchedulerOnScheduler();
});
wait();
}
void TimerThread::joinCpuPool() {
if(d->mCpuPool && !d->mCpuJoined.exchange(true, std::memory_order_acq_rel)) d->mCpuPool->join();
}
void TimerThread::postAndWait(std::function<void()> task) {
if(isSchedulerThread() || !isRunning() || !d->mIoActive.load(std::memory_order_acquire)) {
task();
return;
}
std::mutex mutex;
std::condition_variable cv;
bool done = false;
post([&task, &mutex, &cv, &done]() {
task();
{
std::lock_guard<std::mutex> lock(mutex);
done = true;
}
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [&done]() {
return done;
});
}
void TimerThread::removePlotOnScheduler(Plot* plot) {
mPlots.removeAll(plot);
PlotPrivate* data = plot->d;
data->mRenderEnabled = false;
if(data->mRenderTimer) {
data->mRenderTimer->cancel();
data->mRenderTimer.reset();
}
data->mTimerThread = nullptr;
}
void TimerThread::shutdownOnScheduler() {
for(Plot* plot : mPlots) {
PlotPrivate* data = plot->d;
data->mDestroying.store(true, std::memory_order_release);
data->mRenderEnabled = false;
if(data->mRenderTimer) {
data->mRenderTimer->cancel();
data->mRenderTimer.reset();
}
data->mTimerThread = nullptr;
}
mPlots.clear();
}
void TimerThread::stopSchedulerOnScheduler() {
d->mWorkGuard.reset();
}
void Global::startAllTimeThread() { void Global::startAllTimeThread() {
for (auto &thread: mTimerThreadMap) { for (auto &thread: mTimerThreadMap) {
+7 -3
View File
@@ -22,14 +22,18 @@ namespace YSG {
void run() override; void run() override;
void post(std::function<void()> task); void post(std::function<void()> task);
void postCpu(std::function<void()> task); void postCpu(std::function<void()> task);
void removePlot(Plot* plot);
void shutdown();
bool isSchedulerThread() const; bool isSchedulerThread() const;
asio::io_context& ioContext(); asio::io_context& ioContext();
private: private:
void joinCpuPool();
void postAndWait(std::function<void()> task);
void removePlotOnScheduler(Plot* plot);
void shutdownOnScheduler();
void stopSchedulerOnScheduler();
std::unique_ptr<TimerThreadPrivate> d; std::unique_ptr<TimerThreadPrivate> d;
}; };
class LIB_DECL Global : public QObject, public Psc::Singleton<Global> { class LIB_DECL Global : public QObject, public Psc::Singleton<Global> {
public: public:
int r = qInitResources_resource(); int r = qInitResources_resource();
+76 -24
View File
@@ -20,8 +20,9 @@ namespace YSG {
for(PrePareMutiDataMutex* curLock : mLockList) curLock->unlock(); for(PrePareMutiDataMutex* curLock : mLockList) curLock->unlock();
} }
}; };
static void notifyRenderTaskDone(PlotPrivate* data) {
if(data->mActiveRenderTasks.fetch_sub(1, std::memory_order_acq_rel) == 1) data->mRenderTaskDone.notify_all();
}
void startAllRenderThread() { void startAllRenderThread() {
Global::instance()->startAllTimeThread(); Global::instance()->startAllTimeThread();
} }
@@ -38,9 +39,10 @@ namespace YSG {
d->mTimerThread = thread; d->mTimerThread = thread;
} }
Plot::Plot(){ Plot::Plot() {
d = new PlotPrivate(this); d = new PlotPrivate(this);
setAttribute(Qt::WA_OpaquePaintEvent, true); setAttribute(Qt::WA_OpaquePaintEvent, true);
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
} }
bool Plot::usePerformanceShower() { bool Plot::usePerformanceShower() {
@@ -61,7 +63,15 @@ namespace YSG {
} }
Plot::~Plot() { Plot::~Plot() {
pauseRender(); d->mDestroying.store(true, std::memory_order_release);
d->mRenderEnabled = false;
if(d->mTimerThread) d->mTimerThread->removePlot(this);
{
std::unique_lock<std::mutex> lock(d->mRenderTaskMutex);
d->mRenderTaskDone.wait(lock, [this]() {
return d->mActiveRenderTasks.load(std::memory_order_acquire) == 0;
});
}
delete d; delete d;
} }
@@ -75,28 +85,40 @@ namespace YSG {
} }
void Plot::startRender() const { void Plot::startRender() const {
if(d->mDestroying.load(std::memory_order_acquire)) return;
d->mRenderEnabled = true; d->mRenderEnabled = true;
if(!d->mTimerThread) return; if(!d->mTimerThread) return;
Plot* self = const_cast<Plot*>(this); Plot* self = const_cast<Plot*>(this);
d->mTimerThread->post([self]() { PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([self, privateData]() {
PlotPrivate* d = self->d; PlotPrivate* d = self->d;
if(d->mRenderTimer) { if(!d->mDestroying.load(std::memory_order_acquire)) {
d->mRenderTimer->cancel(); if(d->mRenderTimer) {
self->scheduleRenderTimer(); d->mRenderTimer->cancel();
self->scheduleRenderTimer();
}
self->submitRender();
} }
self->submitRender(); notifyRenderTaskDone(privateData);
}); });
} }
void Plot::pauseRender() const { void Plot::pauseRender() const {
d->mRenderEnabled = false; d->mRenderEnabled = false;
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(!d->mTimerThread) return; if(!d->mTimerThread) return;
Plot* self = const_cast<Plot*>(this); Plot* self = const_cast<Plot*>(this);
d->mTimerThread->post([self]() { PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([self, privateData]() {
PlotPrivate* d = self->d; PlotPrivate* d = self->d;
if(d->mRenderTimer) { if(!d->mDestroying.load(std::memory_order_acquire)) {
d->mRenderTimer->cancel(); if(d->mRenderTimer) {
d->mRenderTimer->cancel();
}
} }
notifyRenderTaskDone(privateData);
}); });
} }
@@ -113,6 +135,7 @@ namespace YSG {
submitRender(); submitRender();
} }
void Plot::submitRender() { void Plot::submitRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(mFirstResize) return; if(mFirstResize) return;
if(!d->mRenderEnabled) return; if(!d->mRenderEnabled) return;
QSize renderSize = d->mRenderSize; QSize renderSize = d->mRenderSize;
@@ -161,10 +184,21 @@ namespace YSG {
TimerThread* thread = d->mTimerThread; TimerThread* thread = d->mTimerThread;
pipeline.jobState = RenderAble::JobState::Running; pipeline.jobState = RenderAble::JobState::Running;
if(thread) { if(thread) {
thread->postCpu([this, color, renderSize, background, version, thread]() { PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
thread->postCpu([this, privateData, color, renderSize, background, version, thread]() {
if(privateData->mDestroying.load(std::memory_order_acquire)) {
notifyRenderTaskDone(privateData);
return;
}
renderColor(color, renderSize, background, version); renderColor(color, renderSize, background, version);
thread->post([this]() { if(privateData->mDestroying.load(std::memory_order_acquire)) {
finishRender(); notifyRenderTaskDone(privateData);
return;
}
thread->post([this, privateData]() {
if(!privateData->mDestroying.load(std::memory_order_acquire)) finishRender();
notifyRenderTaskDone(privateData);
}); });
}); });
} else { } else {
@@ -173,6 +207,7 @@ namespace YSG {
} }
} }
void Plot::finishRender() { void Plot::finishRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
RenderAble::RenderPipeline& pipeline = d->mPipeline; RenderAble::RenderPipeline& pipeline = d->mPipeline;
QRegion updateRegion = pipeline.publishRenderColor(); QRegion updateRegion = pipeline.publishRenderColor();
pipeline.jobState = RenderAble::JobState::Idle; pipeline.jobState = RenderAble::JobState::Idle;
@@ -202,27 +237,37 @@ namespace YSG {
color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size)); color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size));
} }
void Plot::scheduleRenderTimer() { void Plot::scheduleRenderTimer() {
if(!d->mRenderTimer || !d->mRenderEnabled) return; if(d->mDestroying.load(std::memory_order_acquire) || !d->mRenderTimer || !d->mRenderEnabled) return;
int interval = std::max(1, qRound(1000.0 / (double)d->mRefreshTimesPreSecond)); int interval = std::max(1, qRound(1000.0 / (double)d->mRefreshTimesPreSecond));
d->mRenderTimer->expires_after(std::chrono::milliseconds(interval)); d->mRenderTimer->expires_after(std::chrono::milliseconds(interval));
d->mRenderTimer->async_wait([this](const asio::error_code& error) { PlotPrivate* privateData = d;
if(error) return; privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
submitRender(); d->mRenderTimer->async_wait([this, privateData](const asio::error_code& error) {
scheduleRenderTimer(); if(!error && !d->mDestroying.load(std::memory_order_acquire)) {
submitRender();
scheduleRenderTimer();
}
notifyRenderTaskDone(privateData);
}); });
} }
void Plot::markRenderStateDirty() { void Plot::markRenderStateDirty() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
d->mPipeline.markEditState(); d->mPipeline.markEditState();
requestRender(); requestRender();
} }
void Plot::requestRender() { void Plot::requestRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(!d->mTimerThread) return; if(!d->mTimerThread) return;
d->mTimerThread->post([this]() { PlotPrivate* privateData = d;
submitRender(); privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([this, privateData]() {
if(!d->mDestroying.load(std::memory_order_acquire)) submitRender();
notifyRenderTaskDone(privateData);
}); });
} }
void Plot::requestUpdate(const QRegion& region) { void Plot::requestUpdate(const QRegion& region) {
QTimer::singleShot(0, this, [this, region]() { QTimer::singleShot(0, this, [this, region]() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(region.isEmpty()) update(); if(region.isEmpty()) update();
else update(region); else update(region);
}); });
@@ -273,7 +318,11 @@ namespace YSG {
break; break;
} }
case QEvent::Leave: { case QEvent::Leave: {
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->setHoverState(QPoint(), false);
}
}
break; break;
} }
case QEvent::Wheel: { case QEvent::Wheel: {
@@ -283,12 +332,15 @@ namespace YSG {
able->wheelEvent(e); able->wheelEvent(e);
} }
} }
break;
} }
case QEvent::MouseMove: { case QEvent::MouseMove: {
auto e = reinterpret_cast<QMouseEvent*>(event); auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) { for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) { for(RenderAble* able : layer->mRenderAbles) {
if(able->selectTest(e->pos())) { bool selected = able->selectTest(e->pos());
able->setHoverState(e->pos(), selected);
if(selected) {
able->mouseMoveEvent(e); able->mouseMoveEvent(e);
} }
} }
+7 -5
View File
@@ -2,11 +2,12 @@
#include "asio.hpp" #include "asio.hpp"
#include "Plot.h" #include "Plot.h"
#include <atomic>
#include <condition_variable>
#include <QApplication> #include <QApplication>
#include <QThread> #include <QThread>
#include <memory> #include <memory>
#include <mutex>
namespace YSG { namespace YSG {
struct PlotPrivate { struct PlotPrivate {
explicit PlotPrivate(Plot* plot) : q(plot) {}; explicit PlotPrivate(Plot* plot) : q(plot) {};
@@ -15,14 +16,15 @@ namespace YSG {
TimerThread* mTimerThread{}; TimerThread* mTimerThread{};
std::unique_ptr<asio::steady_timer> mRenderTimer; std::unique_ptr<asio::steady_timer> mRenderTimer;
bool mRenderEnabled = false; bool mRenderEnabled = false;
std::atomic_bool mDestroying{false};
std::atomic_int mActiveRenderTasks{0};
std::condition_variable mRenderTaskDone;
std::mutex mRenderTaskMutex;
QSize mRenderSize; QSize mRenderSize;
RenderAble::RenderPipeline mPipeline; RenderAble::RenderPipeline mPipeline;
SpinLock mBufferLock, mRenderLock, mPrepareDataLock, mMustPrepareDataLock; SpinLock mBufferLock, mRenderLock, mPrepareDataLock, mMustPrepareDataLock;
QColor mBackground = Qt::black; QColor mBackground = Qt::black;
PerformanceShower *mShower{}; PerformanceShower *mShower{};
}; };
} }
+2 -3
View File
@@ -4,7 +4,7 @@
namespace YSG { namespace YSG {
void HoverInfoRenderState::drawHover(QPainter* painter, AbsAxis* h, AbsAxis* v) { void HoverInfoRenderState::drawHover(QPainter* painter, AbsAxis* h, AbsAxis* v) {
QPoint pos = QCursor::pos() - h->mPlot->mapToGlobal(QPoint(0, 0)); QPoint pos = hoverInfoPos;
if(!renderAble) { if(!renderAble) {
auto that = dynamic_cast<RenderState*>(this); auto that = dynamic_cast<RenderState*>(this);
renderAble = dynamic_cast<HoverInfoRenderAbleInterFace*>(that->dPtr->qPtr); renderAble = dynamic_cast<HoverInfoRenderAbleInterFace*>(that->dPtr->qPtr);
@@ -26,9 +26,8 @@ namespace YSG {
} }
bool HoverInfoRenderState::hoverOK(RenderAble* able) const { bool HoverInfoRenderState::hoverOK(RenderAble* able) const {
QPoint pos = QCursor::pos() - able->mPlot->mapToGlobal(QPoint(0, 0));
auto tmp = dynamic_cast<HoverInfoRenderAbleInterFace*>(able); auto tmp = dynamic_cast<HoverInfoRenderAbleInterFace*>(able);
return useHoverInfo && able->mPlot->underMouse() && tmp->hoverTest(pos); return useHoverInfo && hoverInfoActive && tmp->hoverTest(hoverInfoPos);
} }
QVector<QString> HoverInfoRenderAbleInterFace::createHoverString(AbsAxis* h, AbsAxis* v, QPoint pos) { QVector<QString> HoverInfoRenderAbleInterFace::createHoverString(AbsAxis* h, AbsAxis* v, QPoint pos) {
+11 -18
View File
@@ -5,7 +5,6 @@
namespace YSG { namespace YSG {
struct HoverInfoRenderState; struct HoverInfoRenderState;
struct HoverInfoRenderAbleInterFace; struct HoverInfoRenderAbleInterFace;
struct LIB_DECL HoverInfoRenderState { struct LIB_DECL HoverInfoRenderState {
virtual ~HoverInfoRenderState() = default; virtual ~HoverInfoRenderState() = default;
HoverInfoRenderState() { HoverInfoRenderState() {
@@ -16,12 +15,12 @@ namespace YSG {
QFont hoverInfoFont; QFont hoverInfoFont;
QPen hoverInfoPen; QPen hoverInfoPen;
bool useHoverInfo = true; bool useHoverInfo = true;
bool hoverInfoActive = false;
QPoint hoverInfoPos;
HoverInfoRenderAbleInterFace *renderAble{}; HoverInfoRenderAbleInterFace *renderAble{};
void drawHover(QPainter* painter, AbsAxis *h, AbsAxis *v); void drawHover(QPainter* painter, AbsAxis *h, AbsAxis *v);
bool hoverOK(RenderAble* able) const; bool hoverOK(RenderAble* able) const;
}; };
struct LIB_DECL HoverInfoRenderAbleInterFace { struct LIB_DECL HoverInfoRenderAbleInterFace {
virtual QVector<QString> createHoverString(AbsAxis* h, AbsAxis* v, QPoint pos); virtual QVector<QString> createHoverString(AbsAxis* h, AbsAxis* v, QPoint pos);
virtual ~HoverInfoRenderAbleInterFace() = default; virtual ~HoverInfoRenderAbleInterFace() = default;
@@ -34,42 +33,38 @@ namespace YSG {
virtual bool hoverTest(QPoint pos) { virtual bool hoverTest(QPoint pos) {
return true; return true;
} }
bool useHoverInfo(SRC src = SRC::Auto) { bool useHoverInfo(SRC src = SRC::Auto) {
return getState(src)->useHoverInfo; return getState(src)->useHoverInfo;
} }
void setUseHoverInfo(bool use) { void setUseHoverInfo(bool use) {
SpinLockGuard g(lock()); SpinLockGuard g(lock());
getState(SRC::Cache)->useHoverInfo = use; getState(SRC::Cache)->useHoverInfo = use;
markHoverInfoDirty();
} }
void setHoverInfoFont(const QFont& font) { void setHoverInfoFont(const QFont& font) {
SpinLockGuard g(lock()); SpinLockGuard g(lock());
getState(SRC::Cache)->hoverInfoFont = font; getState(SRC::Cache)->hoverInfoFont = font;
markHoverInfoDirty();
} }
QFont HoverInfoFont(SRC src = SRC::Auto) { QFont HoverInfoFont(SRC src = SRC::Auto) {
return getState(src)->hoverInfoFont; return getState(src)->hoverInfoFont;
} }
QBrush hoverInfoBackgroundBrush(SRC src = SRC::Auto) { QBrush hoverInfoBackgroundBrush(SRC src = SRC::Auto) {
return getState(src)->hoverInfoBrush; return getState(src)->hoverInfoBrush;
} }
void setHoverInfoBackgroundBrush(const QBrush& brush) { void setHoverInfoBackgroundBrush(const QBrush& brush) {
SpinLockGuard g(lock()); SpinLockGuard g(lock());
getState(SRC::Cache)->hoverInfoBrush = brush.color().isValid() ? brush : Qt::NoBrush; getState(SRC::Cache)->hoverInfoBrush = brush.color().isValid() ? brush : Qt::NoBrush;
markHoverInfoDirty();
} }
QPen hoverInfoPen(SRC src = SRC::Auto) { QPen hoverInfoPen(SRC src = SRC::Auto) {
return getState(src)->hoverInfoPen; return getState(src)->hoverInfoPen;
} }
void setHoverInfoPen(const QPen& pen) { void setHoverInfoPen(const QPen& pen) {
SpinLockGuard g(lock()); SpinLockGuard g(lock());
getState(SRC::Cache)->hoverInfoPen = pen.color().isValid() ? pen : Qt::NoPen; getState(SRC::Cache)->hoverInfoPen = pen.color().isValid() ? pen : Qt::NoPen;
markHoverInfoDirty();
} }
void getHoverInfoContentsMargins(int& left, int& top, int& right, int& bottom, SRC src) { void getHoverInfoContentsMargins(int& left, int& top, int& right, int& bottom, SRC src) {
auto s = getState(src); auto s = getState(src);
left = s->hoverInfoLeft; left = s->hoverInfoLeft;
@@ -85,13 +80,13 @@ namespace YSG {
sc->hoverInfoTop = top; sc->hoverInfoTop = top;
sc->hoverInfoRight = right; sc->hoverInfoRight = right;
sc->hoverInfoBottom = bottom; sc->hoverInfoBottom = bottom;
markHoverInfoDirty();
} }
protected: protected:
virtual HoverInfoRenderState* getState(SRC src) = 0; virtual HoverInfoRenderState* getState(SRC src) = 0;
virtual SpinLock* lock() = 0; virtual SpinLock* lock() = 0;
virtual void markHoverInfoDirty() {}
}; };
struct LIB_DECL HoverInfoIndependRenderAble : HoverInfoRenderAbleInterFace { struct LIB_DECL HoverInfoIndependRenderAble : HoverInfoRenderAbleInterFace {
private: private:
SpinLock mtx; SpinLock mtx;
@@ -116,8 +111,6 @@ namespace YSG {
HoverInfoRenderAbleInterFace::drawHover(painter, h, v); HoverInfoRenderAbleInterFace::drawHover(painter, h, v);
} }
}; };
template <typename That> template <typename That>
struct LIB_DECL HoverInfoRenderAble : HoverInfoRenderAbleInterFace { struct LIB_DECL HoverInfoRenderAble : HoverInfoRenderAbleInterFace {
private: private:
@@ -131,8 +124,8 @@ namespace YSG {
auto t = that(); auto t = that();
return dynamic_cast<HoverInfoRenderState*>(t->dPtr->getState(src)); return dynamic_cast<HoverInfoRenderState*>(t->dPtr->getState(src));
} }
void markHoverInfoDirty() override {
that()->markStateDirty();
}
}; };
} }
+7
View File
@@ -222,5 +222,12 @@ namespace YSG {
if(!ok) return false; if(!ok) return false;
return qAbs(power - sc->powerAxis->pixelToCoord(pos.y(), SRC::Render)) < 4; return qAbs(power - sc->powerAxis->pixelToCoord(pos.y(), SRC::Render)) < 4;
} }
void setHoverState(const QPoint& pos, bool active) override {
SpinLockGuard guard(&mBufferLock);
RenderEditGuard editGuard(this);
SpectrumRenderState* sc = renderStateCache();
sc->hoverInfoPos = pos;
sc->hoverInfoActive = active;
}
}; };
} }
+5 -5
View File
@@ -35,12 +35,12 @@ namespace YSG {
QImage image; QImage image;
int listByteSize{}; int listByteSize{};
bool selectTest(const QPointF& pos) override {return true;} bool selectTest(const QPointF& pos) override {return true;}
void mouseMoveEvent(QMouseEvent* event) override { void setHoverState(const QPoint& pos, bool active) override {
SpinLockGuard guard(&mBufferLock);
RenderEditGuard editGuard(this);
WaterFallRenderState* sc = renderStateCache(); WaterFallRenderState* sc = renderStateCache();
{ sc->hoverInfoPos = pos;
SpinLockGuard guard(&mBufferLock); sc->hoverInfoActive = active;
}
} }
void prepareData() override { void prepareData() override {