8#include <QGraphicsEllipseItem>
12#include <QDragEnterEvent>
14#include <QApplication>
17#include <QInputDialog>
67 static void wrap(QList<VP1Interval>&);
88 bool& allOn,
bool& allOff)
const;
96 : QGraphicsView(parent),
104 m_d->theclass =
this;
106 m_d->popup_enableAllAction = 0;
107 m_d->popup_disableAllAction = 0;
108 m_d->popup_invertAction = 0;
109 m_d->popup_copyAction = 0;
110 m_d->popup_pasteAction = 0;
111 m_d->popup_setNPhiSubMenu = 0;
113 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
114 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
115 setRenderHint(QPainter::Antialiasing,
true);
117 m_d->pen_on.setWidth(0);
118 m_d->pen_on.setBrush(Qt::red);
119 m_d->pen_off.setWidth(0);
120 m_d->pen_off.setBrush(Qt::gray);
121 m_d->brush_on.setColor(Qt::red);
122 m_d->brush_on.setStyle(Qt::SolidPattern);
123 m_d->brush_off.setColor(Qt::gray);
124 m_d->brush_off.setStyle(Qt::SolidPattern);
126 m_d->cacheValid =
false;
128 setFocusPolicy(Qt::NoFocus);
129 setAcceptDrops(
true);
132 m_d->allowCustomNSectors =
true;
133 QList<int> defaultAllowedNSectors;
134 defaultAllowedNSectors << 4 << 5 << 6 << 8 << 9 << 10
135 << 12 << 16 << 24 << 32 << 36 << 48 << 64;
136 m_d->allowedNSectors << 12;
144 QGraphicsScene * oldscene = scene();
160 if (nsectors<4||nsectors>99) {
167 if (!
m_d->allowedNSectors.contains(nsectors) && !
m_d->allowCustomNSectors) {
171 for(
int i = 2; i < 100; ++i) {
172 if (
m_d->allowedNSectors.contains(i*nsectors)) {
177 nsectors = n>0 ? n :
m_d->allowedNSectors.back();
178 }
else if (!
m_d->sectorstatus.isEmpty() && nsectors==
static_cast<int>(
m_d->sectorstatus.count())) {
180 messageDebug(
"!sectorstatus.isEmpty() && nsectors==sectorstatus.count(). Returning...");
185 if (
m_d->sectorstatus.isEmpty() ) {
192 QList<VP1Interval> oldEnabledRanges;
193 if ( !
m_d->sectorstatus.isEmpty() ) {
200 m_d->item2sector.clear();
201 m_d->sectorstatus.clear();
202 QGraphicsScene * oldscene = scene();
203 setScene(
new QGraphicsScene);
207 const double R = 10.0;
208 const double r = (2*
M_PI)*R / nsectors / 1.2;
210 for (
int isector = 0; isector < nsectors; ++isector) {
211 double phi = (isector+0.5)*(2*
M_PI)/nsectors;
212 double x(R*cos(
phi)),
y(-R*sin(
phi));
213 QGraphicsEllipseItem * ellipse = scene()->addEllipse(
x,
y,
r,
r);
214 m_d->item2sector[ellipse]=isector;
217 m_d->sectorstatus.fill(forceAllEnabled,
m_d->item2sector.size());
219 if (!forceAllEnabled)
220 m_d->approximateSectorStatusFromRanges(oldEnabledRanges,
m_d->sectorstatus);
222 fitInView(scene()->sceneRect());
223 m_d->checkForChanges();
230 if (nsectors <= 12) {
232 }
else if(nsectors >= 16 && nsectors < 24) {
233 setFixedSize(120,120);
234 }
else if(nsectors >= 24 && nsectors < 32) {
235 setFixedSize(200,200);
236 }
else if (nsectors >= 32 && nsectors <= 36) {
237 setFixedSize(300,300);
238 }
else if (nsectors > 36) {
239 setFixedSize(400,400);
243 if (
m_d->sectorstatus.isEmpty() ) {
245 messageDebug(
"WARNING. m_d->sectorstatus is still Empty...");
254 return m_d->sectorstatus.count();
260 std::map<QGraphicsEllipseItem*,int>::iterator it, itE =
item2sector.end();
263 it->first->setPen(
pen_on);
275 if (isector<0||isector>=
static_cast<int>(
m_d->sectorstatus.count()))
277 if (
m_d->sectorstatus.at(isector)==status)
279 m_d->sectorstatus[isector]=status;
280 m_d->cacheValid=
false;
281 m_d->checkForChanges();
314 a->setData(nSectors);
327 m_d->ensureMenuInit();
331 QClipboard * clipboard = QApplication::clipboard();
332 m_d->popup_pasteAction->setEnabled(clipboard
333 &&clipboard->mimeData()->hasFormat(
"vp1/enabledphisectors"));
335 for(QAction * setNPhiAct :
m_d->popuplist_setNPhi) {
337 int nSectors = setNPhiAct->data().toInt(&ok);
338 setNPhiAct->setEnabled(ok&&nSectors!=
m_d->sectorstatus.count());
342 QAction * selAct =
m_d->popup_menu->exec(p);
345 if (selAct==
m_d->popup_copyAction) {
346 QMimeData *mimeData =
new QMimeData;
347 mimeData->setData(
"vp1/enabledphisectors",
state());
349 clipboard->setMimeData(mimeData);
352 if (selAct==
m_d->popup_pasteAction) {
353 QByteArray
data = clipboard->mimeData()->data(
"vp1/enabledphisectors");
357 if (selAct==
m_d->popup_enableAllAction) {
358 for (
int i = 0; i <
m_d->sectorstatus.count(); ++i)
359 m_d->sectorstatus[i] =
true;
360 m_d->cacheValid =
false;
361 m_d->checkForChanges();
364 if (selAct==
m_d->popup_disableAllAction) {
365 for (
int i = 0; i <
m_d->sectorstatus.count(); ++i)
366 m_d->sectorstatus[i] =
false;
367 m_d->cacheValid =
false;
368 m_d->checkForChanges();
371 if (selAct==
m_d->popup_invertAction) {
372 for (
int i = 0; i <
m_d->sectorstatus.count(); ++i)
373 m_d->sectorstatus[i] = !
m_d->sectorstatus[i];
374 m_d->cacheValid =
false;
375 m_d->checkForChanges();
378 if (selAct==
m_d->popup_setCustomNPhi) {
381 int nCustomSectors = QInputDialog::getInt(
this,
"Set number of phi sectors",
382 "Set number of phi sectors",
m_d->sectorstatus.count(),4,99,1,&ok);
383 if (ok && nCustomSectors >= 4 && nCustomSectors <= 99 )
387 if (
m_d->popuplist_setNPhi.contains(selAct)) {
389 int nSectors = selAct->data().toInt(&ok);
399 if (event->buttons()==Qt::RightButton) {
404 if (event->button() == Qt::LeftButton)
405 m_d->dragStartPosition =
event->pos();
407 if (event->buttons()!=Qt::LeftButton) {
408 QGraphicsView::mousePressEvent(event);
411 QGraphicsItem *item_ = itemAt(event->pos());
412 QGraphicsEllipseItem * item =
static_cast<QGraphicsEllipseItem*
>(item_);
413 if (!item||
m_d->item2sector.find(item)==
m_d->item2sector.end()) {
414 QGraphicsView::mousePressEvent(event);
417 int isector =
m_d->item2sector[item];
418 if (isector<0||isector>=
static_cast<int>(
m_d->sectorstatus.count())) {
419 QGraphicsView::mousePressEvent(event);
422 m_d->sectorstatus[isector]=!(
m_d->sectorstatus.at(isector));
426 m_d->cacheValid=
false;
427 m_d->checkForChanges();
433 if (!(event->buttons() & Qt::LeftButton))
435 if ((event->pos() -
m_d->dragStartPosition).manhattanLength()
436 < QApplication::startDragDistance())
439 QDrag *drag =
new QDrag(
this);
440 QMimeData *mimeData =
new QMimeData;
446 mimeData->setData(
"vp1/enabledphisectors",
state());
456 drag->setMimeData(mimeData);
457 drag->exec(Qt::CopyAction | Qt::MoveAction);
463 if (event->source()!=
this && event->mimeData()->hasFormat(
"vp1/enabledphisectors"))
464 event->acceptProposedAction();
470 QByteArray
data =
event->mimeData()->data(
"vp1/enabledphisectors");
471 event->acceptProposedAction();
479 fitInView(scene()->sceneRect());
485 if (!
m_d->cacheValid)
486 m_d->checkForChanges();
487 return m_d->cachedAllOn;
494 if (!
m_d->cacheValid)
495 m_d->checkForChanges();
496 return m_d->cachedAllOff;
502 if (l.count()<2||l.front().lower()!=0.0||l.back().upper()!=(2*
M_PI))
504 l.front().setLower(l.back().lower()-(2*
M_PI));
513 theclass->messageVerbose(
"enabledPhiRangesNoCache()");
515 QList<VP1Interval> l;
519 const unsigned int n = secstatus.count();
521 const double dphi = (2*
M_PI)/n;
523 qDebug() <<
"n: " << n <<
" - dphi:" << dphi;
529 for (
unsigned i = 0; i < n; ++i) {
530 const bool status = secstatus[i];
552 theclass->messageDebug(
"exiting enabledPhiRangesNoCache()...");
566 if (!
m_d->cacheValid) {
568 messageDebug(
"Cache not valid. Checking for changes...");
570 m_d->checkForChanges();
572 return m_d->cachedRanges;
579 messageDebug(
"enabledPhiRanges(double phi_min,double phi_max)");
582 if (phi_min>=phi_max)
583 return QList<VP1Interval>();
584 if (phi_max-phi_min>=(2*
M_PI))
594 if (phi_max>(2*
M_PI)) {
609 if (l.front().lower()<0.0) {
611 l.front().setLower(0.0);
619 for (
int i = 0; i < l.count(); ) {
622 if (b <= phi_min||a >= phi_max) {
626 l[i].setLower(phi_min);
628 l[i].setUpper(phi_max);
641 if (!
m_d->cacheValid)
642 m_d->checkForChanges();
644 for(
int i=0;i<
m_d->cachedRanges.count();++i)
645 s+=
m_d->cachedRanges.at(i).toString()+(i==
m_d->cachedRanges.count()-1?
"":
", ");
653 theclass->messageDebug(
"checkForChanges()");
668 for(
int i=0;i<
r.count();++i)
669 s+=
r.at(i).toString()+(i==
r.count()-1?
"":
", ");
670 theclass->messageVerbose(
"Emitting enabledPhiRangesChanged("
671 +
theclass->enabledRangesToString()+
")");
673 emit
theclass->enabledPhiRangesChanged(
r);
681 if (iSector<0||iSector>=nSectors||nSectors<1)
683 if (!
m_d->cacheValid)
684 m_d->checkForChanges();
685 if (
m_d->cachedAllOn)
687 if (
m_d->cachedAllOff)
691 const double dphi = (2*
M_PI)/nSectors;
692 const double epsilon(dphi*1.0e-9);
693 VP1Interval phirange(dphi*iSector+epsilon,dphi*(iSector+1)-epsilon);
697 if (phirange.hasOverlap(enabledrange,2*
M_PI))
707 return QVector<bool>();
708 QVector<bool> v(nSectors,
false);
709 for (
int i = 0; i < nSectors; ++i)
723 int iphi =
static_cast<int>(nSectors*
phi/((2*
M_PI)));
731 QByteArray byteArray;
732 QBuffer buffer(&byteArray);
733 buffer.open(QIODevice::WriteOnly);
734 QDataStream out(&buffer);
736 out <<
m_d->sectorstatus;
754 buffer.open(QIODevice::ReadOnly);
755 QDataStream
state(&buffer);
762 QVector<bool> restored_sectorstatus;
763 state >> restored_sectorstatus;
766 bool save = blockSignals(
true);
767 if (restored_sectorstatus.count()!=
m_d->sectorstatus.count())
769 if (restored_sectorstatus.count()==
m_d->sectorstatus.count()) {
770 m_d->sectorstatus = std::move(restored_sectorstatus);
773 QList<VP1Interval>
r =
m_d->enabledPhiRangesNoCache(restored_sectorstatus,allon, alloff);
775 m_d->sectorstatus.fill(
true);
778 m_d->sectorstatus.fill(
true);
781 m_d->approximateSectorStatusFromRanges(
r,
m_d->sectorstatus);
786 m_d->cacheValid=
false;
787 m_d->checkForChanges();
792 QVector<bool>& target )
794 if (oldEnabledRanges.isEmpty()) {
798 if (oldEnabledRanges.count()==1&&oldEnabledRanges.first().length()>=2*
M_PI*(1.0-1.0e-10)) {
802 const unsigned n = target.size();
804 const double dphi = (2*
M_PI)/n;
805 const double epsilon(dphi*1.0e-9);
806 for (
unsigned i = 0; i < n; ++i) {
807 VP1Interval phirange(dphi*i+epsilon,dphi*(i+1)-epsilon);
808 for(
const VP1Interval& oldrange : oldEnabledRanges) {
809 if (phirange.hasOverlap(oldrange,2*
M_PI)) {
821 event->acceptProposedAction();
838 if (allowedNSectors.isEmpty()) {
844 for(
int s : allowedNSectors) {
853 if (allowCustom&&!allowedNSectors.contains(
m_d->sectorstatus.count())) {
854 allowedNSectors <<
m_d->sectorstatus.count();
857 m_d->allowCustomNSectors = allowCustom;
859 std::sort(allowedNSectors.begin(), allowedNSectors.end());
860 if (
m_d->allowedNSectors==allowedNSectors) {
863 m_d->allowedNSectors=std::move(allowedNSectors);
864 if (
m_d->popup_menu) {
865 m_d->addMenuEntriesForSetNPhi();
868 if (!
m_d->allowedNSectors.contains(
m_d->sectorstatus.count())) {
872 int checkA =
m_d->sectorstatus.isEmpty();
873 int checkB =
m_d->sectorstatus.count();
875 messageDebug(
"check - sectorstatus.isEmpty? " +
str(checkA + checkB) );
Scalar phi() const
phi method
char data[hepevt_bytes_allocation_ATLAS]
VP1HelperClassBase(IVP1System *sys=0, QString helpername="")
void messageVerbose(const QString &) const
void messageDebug(const QString &) const
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.