修复关闭时候的错误
This commit is contained in:
@@ -88,7 +88,6 @@ namespace YSG {
|
||||
RenderEditGuard::~RenderEditGuard() {
|
||||
if(mData && mData->qPtr) mData->qPtr->markStateDirty();
|
||||
}
|
||||
|
||||
void RenderAble::init(Plot* plot, QString layerName) {
|
||||
if(layerName.isEmpty()) {
|
||||
layerName = plot->mDefaultLayerName;
|
||||
@@ -114,8 +113,6 @@ namespace YSG {
|
||||
if(dPtr && dPtr->mRenderStateCache) ++dPtr->mRenderStateCache->version;
|
||||
if(mPlot) mPlot->markRenderStateDirty();
|
||||
}
|
||||
|
||||
|
||||
bool RenderAble::ok() const {
|
||||
return dPtr->mRenderStart && mPlot && !mPlot->mFirstResize && !mPlot->mFirstPrepareData;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ protected:
|
||||
virtual void mousePressEvent(QMouseEvent* event) {}
|
||||
virtual void mouseMoveEvent(QMouseEvent* event) {}
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event) {}
|
||||
virtual void setHoverState(const QPoint& pos, bool active) {}
|
||||
virtual void keyPressEvent(QKeyEvent* event) {}
|
||||
virtual void keyReleaseEvent(QKeyEvent* event) {}
|
||||
virtual void firstResizeEvent(QResizeEvent* event) {}
|
||||
@@ -153,6 +154,9 @@ struct RenderAble {
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event) {
|
||||
dPtr->mouseReleaseEvent(event);
|
||||
}
|
||||
virtual void setHoverState(const QPoint& pos, bool active) {
|
||||
dPtr->setHoverState(pos, active);
|
||||
}
|
||||
virtual void keyPressEvent(QKeyEvent* event) {
|
||||
dPtr->keyPressEvent(event);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "asio.hpp"
|
||||
#include "Global.h"
|
||||
#include <QApplication>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#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::thread_pool> mCpuPool;
|
||||
std::thread::id mSchedulerThreadId;
|
||||
std::atomic_bool mIoActive{false};
|
||||
std::atomic_bool mCpuJoined{false};
|
||||
};
|
||||
|
||||
TimerThread::TimerThread() : d(std::make_unique<TimerThreadPrivate>()) {
|
||||
connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() {
|
||||
if (isRunning()) {
|
||||
d->mIoContext.stop();
|
||||
if(d->mCpuPool) d->mCpuPool->stop();
|
||||
wait();
|
||||
}
|
||||
shutdown();
|
||||
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());
|
||||
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->mCpuJoined.store(false, std::memory_order_release);
|
||||
d->mIoActive.store(true, std::memory_order_release);
|
||||
for (auto &plot: mPlots) {
|
||||
plot->d->mTimerThread = this;
|
||||
plot->d->mRenderTimer = std::make_unique<asio::steady_timer>(d->mIoContext);
|
||||
@@ -39,17 +42,15 @@ namespace YSG {
|
||||
plot->requestRender();
|
||||
}
|
||||
d->mIoContext.run();
|
||||
d->mIoActive.store(false, std::memory_order_release);
|
||||
for (auto &plot: mPlots) {
|
||||
if(plot->d->mRenderTimer) {
|
||||
plot->d->mRenderTimer->cancel();
|
||||
plot->d->mRenderTimer.reset();
|
||||
}
|
||||
}
|
||||
if(d->mCpuPool) {
|
||||
d->mCpuPool->stop();
|
||||
d->mCpuPool->join();
|
||||
d->mCpuPool.reset();
|
||||
}
|
||||
joinCpuPool();
|
||||
d->mCpuPool.reset();
|
||||
d->mWorkGuard.reset();
|
||||
}
|
||||
void TimerThread::post(std::function<void()> task) {
|
||||
@@ -68,6 +69,83 @@ namespace YSG {
|
||||
asio::io_context& TimerThread::ioContext() {
|
||||
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() {
|
||||
for (auto &thread: mTimerThreadMap) {
|
||||
|
||||
@@ -22,14 +22,18 @@ namespace YSG {
|
||||
void run() override;
|
||||
void post(std::function<void()> task);
|
||||
void postCpu(std::function<void()> task);
|
||||
void removePlot(Plot* plot);
|
||||
void shutdown();
|
||||
bool isSchedulerThread() const;
|
||||
asio::io_context& ioContext();
|
||||
private:
|
||||
void joinCpuPool();
|
||||
void postAndWait(std::function<void()> task);
|
||||
void removePlotOnScheduler(Plot* plot);
|
||||
void shutdownOnScheduler();
|
||||
void stopSchedulerOnScheduler();
|
||||
std::unique_ptr<TimerThreadPrivate> d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LIB_DECL Global : public QObject, public Psc::Singleton<Global> {
|
||||
public:
|
||||
int r = qInitResources_resource();
|
||||
|
||||
@@ -20,8 +20,9 @@ namespace YSG {
|
||||
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() {
|
||||
Global::instance()->startAllTimeThread();
|
||||
}
|
||||
@@ -38,9 +39,10 @@ namespace YSG {
|
||||
d->mTimerThread = thread;
|
||||
}
|
||||
|
||||
Plot::Plot(){
|
||||
Plot::Plot() {
|
||||
d = new PlotPrivate(this);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setMouseTracking(true);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
bool Plot::usePerformanceShower() {
|
||||
@@ -61,7 +63,15 @@ namespace YSG {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -75,28 +85,40 @@ namespace YSG {
|
||||
}
|
||||
|
||||
void Plot::startRender() const {
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
d->mRenderEnabled = true;
|
||||
if(!d->mTimerThread) return;
|
||||
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;
|
||||
if(d->mRenderTimer) {
|
||||
d->mRenderTimer->cancel();
|
||||
self->scheduleRenderTimer();
|
||||
if(!d->mDestroying.load(std::memory_order_acquire)) {
|
||||
if(d->mRenderTimer) {
|
||||
d->mRenderTimer->cancel();
|
||||
self->scheduleRenderTimer();
|
||||
}
|
||||
self->submitRender();
|
||||
}
|
||||
self->submitRender();
|
||||
notifyRenderTaskDone(privateData);
|
||||
});
|
||||
}
|
||||
|
||||
void Plot::pauseRender() const {
|
||||
d->mRenderEnabled = false;
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
if(!d->mTimerThread) return;
|
||||
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;
|
||||
if(d->mRenderTimer) {
|
||||
d->mRenderTimer->cancel();
|
||||
if(!d->mDestroying.load(std::memory_order_acquire)) {
|
||||
if(d->mRenderTimer) {
|
||||
d->mRenderTimer->cancel();
|
||||
}
|
||||
}
|
||||
notifyRenderTaskDone(privateData);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,6 +135,7 @@ namespace YSG {
|
||||
submitRender();
|
||||
}
|
||||
void Plot::submitRender() {
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
if(mFirstResize) return;
|
||||
if(!d->mRenderEnabled) return;
|
||||
QSize renderSize = d->mRenderSize;
|
||||
@@ -161,10 +184,21 @@ namespace YSG {
|
||||
TimerThread* thread = d->mTimerThread;
|
||||
pipeline.jobState = RenderAble::JobState::Running;
|
||||
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);
|
||||
thread->post([this]() {
|
||||
finishRender();
|
||||
if(privateData->mDestroying.load(std::memory_order_acquire)) {
|
||||
notifyRenderTaskDone(privateData);
|
||||
return;
|
||||
}
|
||||
thread->post([this, privateData]() {
|
||||
if(!privateData->mDestroying.load(std::memory_order_acquire)) finishRender();
|
||||
notifyRenderTaskDone(privateData);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -173,6 +207,7 @@ namespace YSG {
|
||||
}
|
||||
}
|
||||
void Plot::finishRender() {
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
RenderAble::RenderPipeline& pipeline = d->mPipeline;
|
||||
QRegion updateRegion = pipeline.publishRenderColor();
|
||||
pipeline.jobState = RenderAble::JobState::Idle;
|
||||
@@ -202,27 +237,37 @@ namespace YSG {
|
||||
color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size));
|
||||
}
|
||||
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));
|
||||
d->mRenderTimer->expires_after(std::chrono::milliseconds(interval));
|
||||
d->mRenderTimer->async_wait([this](const asio::error_code& error) {
|
||||
if(error) return;
|
||||
submitRender();
|
||||
scheduleRenderTimer();
|
||||
PlotPrivate* privateData = d;
|
||||
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
|
||||
d->mRenderTimer->async_wait([this, privateData](const asio::error_code& error) {
|
||||
if(!error && !d->mDestroying.load(std::memory_order_acquire)) {
|
||||
submitRender();
|
||||
scheduleRenderTimer();
|
||||
}
|
||||
notifyRenderTaskDone(privateData);
|
||||
});
|
||||
}
|
||||
void Plot::markRenderStateDirty() {
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
d->mPipeline.markEditState();
|
||||
requestRender();
|
||||
}
|
||||
void Plot::requestRender() {
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
if(!d->mTimerThread) return;
|
||||
d->mTimerThread->post([this]() {
|
||||
submitRender();
|
||||
PlotPrivate* privateData = d;
|
||||
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) {
|
||||
QTimer::singleShot(0, this, [this, region]() {
|
||||
if(d->mDestroying.load(std::memory_order_acquire)) return;
|
||||
if(region.isEmpty()) update();
|
||||
else update(region);
|
||||
});
|
||||
@@ -273,7 +318,11 @@ namespace YSG {
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
|
||||
for(Layer* layer : mLayerList) {
|
||||
for(RenderAble* able : layer->mRenderAbles) {
|
||||
able->setHoverState(QPoint(), false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::Wheel: {
|
||||
@@ -283,12 +332,15 @@ namespace YSG {
|
||||
able->wheelEvent(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove: {
|
||||
auto e = reinterpret_cast<QMouseEvent*>(event);
|
||||
for(Layer* layer : mLayerList) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
#include "asio.hpp"
|
||||
#include "Plot.h"
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <memory>
|
||||
|
||||
|
||||
#include <mutex>
|
||||
namespace YSG {
|
||||
struct PlotPrivate {
|
||||
explicit PlotPrivate(Plot* plot) : q(plot) {};
|
||||
@@ -15,14 +16,15 @@ namespace YSG {
|
||||
TimerThread* mTimerThread{};
|
||||
std::unique_ptr<asio::steady_timer> mRenderTimer;
|
||||
bool mRenderEnabled = false;
|
||||
std::atomic_bool mDestroying{false};
|
||||
std::atomic_int mActiveRenderTasks{0};
|
||||
std::condition_variable mRenderTaskDone;
|
||||
std::mutex mRenderTaskMutex;
|
||||
QSize mRenderSize;
|
||||
RenderAble::RenderPipeline mPipeline;
|
||||
SpinLock mBufferLock, mRenderLock, mPrepareDataLock, mMustPrepareDataLock;
|
||||
QColor mBackground = Qt::black;
|
||||
PerformanceShower *mShower{};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
namespace YSG {
|
||||
void HoverInfoRenderState::drawHover(QPainter* painter, AbsAxis* h, AbsAxis* v) {
|
||||
QPoint pos = QCursor::pos() - h->mPlot->mapToGlobal(QPoint(0, 0));
|
||||
QPoint pos = hoverInfoPos;
|
||||
if(!renderAble) {
|
||||
auto that = dynamic_cast<RenderState*>(this);
|
||||
renderAble = dynamic_cast<HoverInfoRenderAbleInterFace*>(that->dPtr->qPtr);
|
||||
@@ -26,9 +26,8 @@ namespace YSG {
|
||||
}
|
||||
|
||||
bool HoverInfoRenderState::hoverOK(RenderAble* able) const {
|
||||
QPoint pos = QCursor::pos() - able->mPlot->mapToGlobal(QPoint(0, 0));
|
||||
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) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
namespace YSG {
|
||||
struct HoverInfoRenderState;
|
||||
struct HoverInfoRenderAbleInterFace;
|
||||
|
||||
struct LIB_DECL HoverInfoRenderState {
|
||||
virtual ~HoverInfoRenderState() = default;
|
||||
HoverInfoRenderState() {
|
||||
@@ -16,12 +15,12 @@ namespace YSG {
|
||||
QFont hoverInfoFont;
|
||||
QPen hoverInfoPen;
|
||||
bool useHoverInfo = true;
|
||||
bool hoverInfoActive = false;
|
||||
QPoint hoverInfoPos;
|
||||
HoverInfoRenderAbleInterFace *renderAble{};
|
||||
void drawHover(QPainter* painter, AbsAxis *h, AbsAxis *v);
|
||||
bool hoverOK(RenderAble* able) const;
|
||||
};
|
||||
|
||||
|
||||
struct LIB_DECL HoverInfoRenderAbleInterFace {
|
||||
virtual QVector<QString> createHoverString(AbsAxis* h, AbsAxis* v, QPoint pos);
|
||||
virtual ~HoverInfoRenderAbleInterFace() = default;
|
||||
@@ -34,42 +33,38 @@ namespace YSG {
|
||||
virtual bool hoverTest(QPoint pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool useHoverInfo(SRC src = SRC::Auto) {
|
||||
return getState(src)->useHoverInfo;
|
||||
}
|
||||
void setUseHoverInfo(bool use) {
|
||||
SpinLockGuard g(lock());
|
||||
getState(SRC::Cache)->useHoverInfo = use;
|
||||
markHoverInfoDirty();
|
||||
}
|
||||
|
||||
void setHoverInfoFont(const QFont& font) {
|
||||
SpinLockGuard g(lock());
|
||||
getState(SRC::Cache)->hoverInfoFont = font;
|
||||
markHoverInfoDirty();
|
||||
}
|
||||
|
||||
QFont HoverInfoFont(SRC src = SRC::Auto) {
|
||||
return getState(src)->hoverInfoFont;
|
||||
}
|
||||
|
||||
QBrush hoverInfoBackgroundBrush(SRC src = SRC::Auto) {
|
||||
return getState(src)->hoverInfoBrush;
|
||||
}
|
||||
|
||||
void setHoverInfoBackgroundBrush(const QBrush& brush) {
|
||||
SpinLockGuard g(lock());
|
||||
getState(SRC::Cache)->hoverInfoBrush = brush.color().isValid() ? brush : Qt::NoBrush;
|
||||
markHoverInfoDirty();
|
||||
}
|
||||
|
||||
QPen hoverInfoPen(SRC src = SRC::Auto) {
|
||||
return getState(src)->hoverInfoPen;
|
||||
}
|
||||
|
||||
void setHoverInfoPen(const QPen& pen) {
|
||||
SpinLockGuard g(lock());
|
||||
getState(SRC::Cache)->hoverInfoPen = pen.color().isValid() ? pen : Qt::NoPen;
|
||||
markHoverInfoDirty();
|
||||
}
|
||||
|
||||
void getHoverInfoContentsMargins(int& left, int& top, int& right, int& bottom, SRC src) {
|
||||
auto s = getState(src);
|
||||
left = s->hoverInfoLeft;
|
||||
@@ -85,13 +80,13 @@ namespace YSG {
|
||||
sc->hoverInfoTop = top;
|
||||
sc->hoverInfoRight = right;
|
||||
sc->hoverInfoBottom = bottom;
|
||||
markHoverInfoDirty();
|
||||
}
|
||||
protected:
|
||||
virtual HoverInfoRenderState* getState(SRC src) = 0;
|
||||
virtual SpinLock* lock() = 0;
|
||||
virtual void markHoverInfoDirty() {}
|
||||
};
|
||||
|
||||
|
||||
struct LIB_DECL HoverInfoIndependRenderAble : HoverInfoRenderAbleInterFace {
|
||||
private:
|
||||
SpinLock mtx;
|
||||
@@ -116,8 +111,6 @@ namespace YSG {
|
||||
HoverInfoRenderAbleInterFace::drawHover(painter, h, v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename That>
|
||||
struct LIB_DECL HoverInfoRenderAble : HoverInfoRenderAbleInterFace {
|
||||
private:
|
||||
@@ -131,8 +124,8 @@ namespace YSG {
|
||||
auto t = that();
|
||||
return dynamic_cast<HoverInfoRenderState*>(t->dPtr->getState(src));
|
||||
}
|
||||
void markHoverInfoDirty() override {
|
||||
that()->markStateDirty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -222,5 +222,12 @@ namespace YSG {
|
||||
if(!ok) return false;
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ namespace YSG {
|
||||
QImage image;
|
||||
int listByteSize{};
|
||||
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();
|
||||
{
|
||||
SpinLockGuard guard(&mBufferLock);
|
||||
|
||||
}
|
||||
sc->hoverInfoPos = pos;
|
||||
sc->hoverInfoActive = active;
|
||||
}
|
||||
|
||||
void prepareData() override {
|
||||
|
||||
Reference in New Issue
Block a user