source: trunk/FACT++/gui/FactGui.h @ 10770

Last change on this file since 10770 was 10770, checked in by tbretz, 9 years ago
Fixed some unimportant compiler warnings.
File size: 62.7 KB
Line 
1#ifndef FACT_FactGui
2#define FACT_FactGui
3
4#include "MainWindow.h"
5
6#include <iomanip>
7#include <valarray>
8
9#include <boost/bind.hpp>
10
11#include <QTimer>
12#include <QStandardItemModel>
13
14#include "CheckBoxDelegate.h"
15
16#include "src/Dim.h"
17#include "src/Converter.h"
18#include "src/HeadersFTM.h"
19#include "src/HeadersFAD.h"
20#include "src/DimNetwork.h"
21#include "src/tools.h"
22
23#include "TROOT.h"
24#include "TSystem.h"
25#include "TGraph.h"
26#include "TH1.h"
27#include "TStyle.h"
28#include "TMarker.h"
29#include "TColor.h"
30
31using namespace std;
32
33// #########################################################################
34
35class Camera : public TObject
36{
37    typedef pair<double,double> Position;
38    typedef vector<Position> Positions;
39
40    Positions fGeom;
41
42    void CreatePalette()
43    {
44        /*
45         double ss[5] = {0., 0.10, 0.45, 0.75, 1.00};
46         double rr[5] = {0., 0.35, 0.85, 1.00, 1.00};
47         double gg[5] = {0., 0.10, 0.20, 0.73, 1.00};
48         double bb[5] = {0., 0.03, 0.06, 0.00, 1.00};
49         */
50        double ss[5] = {0., 0.25, 0.50, 0.75, 1.00};
51        double rr[5] = {0., 0.00, 0.00, 1.00, 1.00};
52        double gg[5] = {0., 0.00, 1.00, 0.00, 1.00};
53        double bb[5] = {0., 1.00, 0.00, 0.00, 1.00};
54
55        const Int_t nn = 1440;
56
57        Int_t idx = TColor::CreateGradientColorTable(5, ss, rr, gg, bb, nn);
58        for (int i=0; i<nn; i++)
59            fPalette.push_back(idx++);
60    }
61
62    void CreateGeometry()
63    {
64        const double gsSin60 = sqrt(3.)/2;
65
66        const int rings = 23;
67
68        //  add the first pixel to the list
69
70        fGeom.push_back(make_pair(0, -0.5));
71
72        for (int ring=1; ring<=rings; ring++)
73        {
74            for (int s=0; s<6; s++)
75            {
76                for (int i=1; i<=ring; i++)
77                {
78                    double xx, yy;
79                    switch (s)
80                    {
81                    case 0: // Direction South East
82                        xx = (ring+i)*0.5;
83                        yy = (-ring+i)*gsSin60;
84                        break;
85
86                    case 1: // Direction North East
87                        xx = ring-i*0.5;
88                        yy = i*gsSin60;
89                        break;
90
91                    case 2: // Direction North
92                        xx = ring*0.5-i;
93                        yy = ring*gsSin60;
94                        break;
95
96                    case 3: // Direction North West
97                        xx = -(ring+i)*0.5;
98                        yy = (ring-i)*gsSin60;
99                        break;
100
101                    case 4: // Direction South West
102                        xx = 0.5*i-ring;
103                        yy = -i*gsSin60;
104                        break;
105
106                    case 5: // Direction South
107                        xx = i-ring*0.5;
108                        yy = -ring*gsSin60;
109                        break;
110                    }
111
112                    if (xx*xx + yy*yy - xx > 395.75)
113                        continue;
114
115                    fGeom.push_back(make_pair(yy, xx-0.5));
116                }
117            }
118        }
119    }
120
121    valarray<double> fData;
122    vector<bool>   fBold;
123    vector<bool>   fEnable;
124
125    int fWhite;
126
127public:
128    Camera() : fData(1440), fBold(1440), fEnable(1440), fWhite(-1)
129    {
130        CreatePalette();
131        CreateGeometry();
132
133        for (int i=0; i<1440; i++)
134        {
135            fData[i] = i;
136            fBold[i]=false;
137            fEnable[i]=true;
138        }
139    }
140
141    void Reset() { fBold.assign(1440, false); }
142
143    void SetBold(int idx) { fBold[idx]=true; }
144    void SetWhite(int idx) { fWhite=idx; }
145    void SetEnable(int idx, bool b) { fEnable[idx]=b; }
146    void Toggle(int idx) { fEnable[idx]=!fEnable[idx]; }
147    double GetData(int idx) const { return fData[idx]; }
148
149    const char *GetName() const { return "Camera"; }
150
151    vector<Int_t> fPalette;
152
153    void Paint(const Position &p)
154    {
155        static const Double_t fgCos60 = 0.5;        // TMath::Cos(60/TMath::RadToDeg());
156        static const Double_t fgSin60 = sqrt(3.)/2; // TMath::Sin(60/TMath::RadToDeg());
157
158        static const Double_t fgDy[6] = { fgCos60,   0.,         -fgCos60,   -fgCos60,    0.,           fgCos60   };
159        static const Double_t fgDx[6] = { fgSin60/3, fgSin60*2/3, fgSin60/3, -fgSin60/3, -fgSin60*2/3, -fgSin60/3 };
160
161        //
162        //  calculate the positions of the pixel corners
163        //
164        Double_t x[7], y[7];
165        for (Int_t i=0; i<7; i++)
166        {
167            x[i] = p.first  + fgDx[i%6];
168            y[i] = p.second + fgDy[i%6];
169        }
170
171        gPad->PaintFillArea(6, x, y);
172        gPad->PaintPolyLine(7, x, y);
173
174    }
175
176    void Paint(Option_t *)
177    {
178        gStyle->SetPalette(fPalette.size(), fPalette.data());
179
180
181        const double r   = double(gPad->GetWw())/gPad->GetWh();
182        const double max = 20.5; // 20.5 rings in x and y
183
184        if (r>1)
185            gPad->Range(-r*max, -max, r*max, max);
186        else
187            gPad->Range(-max, -max/r, max, max/r);
188
189
190        const double min   = fData.min();
191        const double scale = fData.max()==fData.min() ? 1 : fData.max()-fData.min();
192
193        TAttFill fill(0, 1001);
194        TAttLine line;
195
196        int cnt=0;
197        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
198        {
199            if (fBold[cnt])
200                continue;
201
202            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
203
204            if (fEnable[cnt])
205                fill.SetFillColor(gStyle->GetColorPalette(col));
206            else
207                fill.SetFillColor(kWhite);
208
209            fill.Modify();
210
211            Paint(*p);
212        }
213
214        line.SetLineWidth(2);
215        line.Modify();
216
217        cnt = 0;
218        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
219        {
220            if (!fBold[cnt])
221                continue;
222
223            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
224
225            if (fEnable[cnt])
226                fill.SetFillColor(gStyle->GetColorPalette(col));
227            else
228                fill.SetFillColor(kWhite);
229            fill.Modify();
230
231            Paint(*p);
232        }
233
234        TMarker m(0,0,kStar);
235        m.DrawMarker(0, 0);
236
237        if (fWhite<0)
238            return;
239
240        const Position &p = fGeom[fWhite];
241
242        line.SetLineColor(kWhite);
243        line.Modify();
244
245        const int col = (fData[fWhite]-min)/scale*(fPalette.size()-1);
246
247        if (fEnable[fWhite])
248            fill.SetFillColor(gStyle->GetColorPalette(col));
249        else
250            fill.SetFillColor(kWhite);
251        fill.Modify();
252
253        Paint(p);
254    }
255
256    int GetIdx(float px, float py) const
257    {
258        static const double sqrt3 = sqrt(3);
259
260        int idx = 0;
261        for (Positions::const_iterator p=fGeom.begin(); p!=fGeom.end(); p++, idx++)
262        {
263            const Double_t dy = py - p->second;
264            if (fabs(dy)>0.5)
265                continue;
266
267            const Double_t dx = px - p->first;
268
269            if  (TMath::Abs(dy + dx*sqrt3) > 1)
270                continue;
271
272            if  (TMath::Abs(dy - dx*sqrt3) > 1)
273                continue;
274
275            return idx;
276        }
277        return -1;
278    }
279
280    char* GetObjectInfo(Int_t px, Int_t py) const
281    {
282        static stringstream stream;
283        static string       str;
284
285        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
286        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
287
288        const int idx = GetIdx(x, y);
289
290        stream.seekp(0);
291        if (idx>=0)
292            stream << "Pixel=" << idx << "   Data=" << fData[idx] << '\0';
293
294        str = stream.str();
295        return const_cast<char*>(str.c_str());
296    }
297
298    Int_t DistancetoPrimitive(Int_t px, Int_t py)
299    {
300        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
301        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
302
303        return GetIdx(x, y)>=0 ? 0 : 99999;
304    }
305
306    void SetData(const valarray<double> &data)
307    {
308        fData = data;
309    }
310};
311
312// #########################################################################
313
314
315class FactGui : public MainWindow, public DimNetwork
316{
317private:
318    class FunctionEvent : public QEvent
319    {
320    public:
321        boost::function<void(const QEvent &)> fFunction;
322
323        FunctionEvent(const boost::function<void(const QEvent &)> &f)
324            : QEvent((QEvent::Type)QEvent::registerEventType()),
325            fFunction(f) { }
326
327        bool Exec() { fFunction(*this); return true; }
328    };
329
330    valarray<int8_t> fFtuStatus;
331
332    DimStampedInfo fDimDNS;
333
334    DimStampedInfo fDimLoggerStats;
335    DimStampedInfo fDimLoggerFilenameNight;
336    DimStampedInfo fDimLoggerFilenameRun;
337    DimStampedInfo fDimLoggerNumSubs;
338
339    DimStampedInfo fDimFtmPassport;
340    DimStampedInfo fDimFtmTriggerCounter;
341    DimStampedInfo fDimFtmError;
342    DimStampedInfo fDimFtmFtuList;
343    DimStampedInfo fDimFtmStaticData;
344    DimStampedInfo fDimFtmDynamicData;
345    DimStampedInfo fDimFtmCounter;
346
347    DimStampedInfo fDimFadPassport;
348    DimStampedInfo fDimFadTemperatures;
349    DimStampedInfo fDimFadSetup;
350
351    map<string, DimInfo*> fServices;
352
353    // ========================== LED Colors ================================
354
355    enum LedColor_t
356    {
357        kLedRed,
358        kLedGreen,
359        kLedYellow,
360        kLedOrange,
361        kLedGray
362    };
363
364    void SetLedColor(QPushButton *button, LedColor_t col, const Time &t)
365    {
366        switch (col)
367        {
368        case kLedRed:
369            button->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
370            break;
371
372        case kLedGreen:
373            button->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
374            break;
375
376        case kLedYellow:
377            button->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
378            break;
379
380        case kLedOrange:
381            button->setIcon(QIcon(":/Resources/icons/orange circle 1.png"));
382            break;
383
384        case kLedGray:
385            button->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
386            break;
387        }
388
389        //button->setToolTip("Last change: "+QDateTime::currentDateTimeUtc().toString()+" UTC");
390        button->setToolTip(("Last change: "+t.GetAsStr()+" UTC").c_str());
391    }
392
393    // ===================== Services and Commands ==========================
394
395    QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd)
396    {
397        QListView *servers     = iscmd ? fDimCmdServers     : fDimSvcServers;
398        QListView *services    = iscmd ? fDimCmdCommands    : fDimSvcServices;
399        QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription;
400
401        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
402        if (!m)
403        {
404            m = new QStandardItemModel(this);
405            servers->setModel(m);
406            services->setModel(m);
407            description->setModel(m);
408        }
409
410        QList<QStandardItem*> l = m->findItems(server.c_str());
411
412        if (l.size()>1)
413        {
414            cout << "hae" << endl;
415            return 0;
416        }
417
418        QStandardItem *col = l.size()==0 ? NULL : l[0];
419
420        if (!col)
421        {
422            col = new QStandardItem(server.c_str());
423            m->appendRow(col);
424
425            if (!services->rootIndex().isValid())
426            {
427                services->setRootIndex(col->index());
428                servers->setCurrentIndex(col->index());
429            }
430        }
431
432        QStandardItem *item = 0;
433        for (int i=0; i<col->rowCount(); i++)
434        {
435            QStandardItem *coli = col->child(i);
436            if (coli->text().toStdString()==service)
437                return coli;
438        }
439
440        item = new QStandardItem(service.c_str());
441        col->appendRow(item);
442        col->sortChildren(0);
443
444        if (!description->rootIndex().isValid())
445        {
446            description->setRootIndex(item->index());
447            services->setCurrentIndex(item->index());
448        }
449
450        if (!iscmd)
451            item->setCheckable(true);
452
453        return item;
454    }
455
456    void AddDescription(QStandardItem *item, const vector<Description> &vec)
457    {
458        if (!item)
459            return;
460        if (vec.size()==0)
461            return;
462
463        item->setToolTip(vec[0].comment.c_str());
464
465        const string str = Description::GetHtmlDescription(vec);
466
467        QStandardItem *desc = new QStandardItem(str.c_str());
468        desc->setSelectable(false);
469        item->setChild(0, 0, desc);
470    }
471
472    void AddServer(const std::string &s)
473    {
474        DimNetwork::AddServer(s);
475
476        QApplication::postEvent(this,
477           new FunctionEvent(boost::bind(&FactGui::handleAddServer, this, s)));
478    }
479
480    void RemoveServer(const std::string &s)
481    {
482        UnsubscribeServer(s);
483
484        DimNetwork::RemoveServer(s);
485
486        QApplication::postEvent(this,
487           new FunctionEvent(boost::bind(&FactGui::handleRemoveServer, this, s)));
488    }
489
490    void RemoveAllServers()
491    {
492        UnsubscribeAllServers();
493
494        vector<string> v = GetServerList();
495        for (vector<string>::iterator i=v.begin(); i<v.end(); i++)
496            QApplication::postEvent(this,
497                                    new FunctionEvent(boost::bind(&FactGui::handleStateOffline, this, *i)));
498
499        DimNetwork::RemoveAllServers();
500
501        QApplication::postEvent(this,
502           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServers, this)));
503    }
504
505    void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
506    {
507        QApplication::postEvent(this,
508           new FunctionEvent(boost::bind(&FactGui::handleAddService, this, server, service, fmt, iscmd)));
509    }
510
511    void RemoveService(const std::string &server, const std::string &service, bool iscmd)
512    {
513        if (fServices.find(server+'/'+service)!=fServices.end())
514            UnsubscribeService(server+'/'+service);
515
516        QApplication::postEvent(this,
517           new FunctionEvent(boost::bind(&FactGui::handleRemoveService, this, server, service, iscmd)));
518    }
519
520    void RemoveAllServices(const std::string &server)
521    {
522        UnsubscribeServer(server);
523
524        QApplication::postEvent(this,
525           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServices, this, server)));
526    }
527
528    void AddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
529    {
530        QApplication::postEvent(this,
531           new FunctionEvent(boost::bind(&FactGui::handleAddDescription, this, server, service, vec)));
532    }
533
534    // ======================================================================
535
536    void handleAddServer(const std::string &server)
537    {
538        const State s = GetState(server, GetCurrentState(server));
539        handleStateChanged(Time(), server, s);
540    }
541
542    void handleRemoveServer(const string &server)
543    {
544        handleStateOffline(server);
545        handleRemoveAllServices(server);
546    }
547
548    void handleRemoveAllServers()
549    {
550        QStandardItemModel *m = 0;
551        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
552            m->removeRows(0, m->rowCount());
553
554        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
555            m->removeRows(0, m->rowCount());
556    }
557
558    void handleAddService(const std::string &server, const std::string &service, const std::string &/*fmt*/, bool iscmd)
559    {
560        QStandardItem *item = AddServiceItem(server, service, iscmd);
561        const vector<Description> v = GetDescription(server, service);
562        AddDescription(item, v);
563    }
564
565    void handleRemoveService(const std::string &server, const std::string &service, bool iscmd)
566    {
567        QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers;
568
569        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
570        if (!m)
571            return;
572
573        QList<QStandardItem*> l = m->findItems(server.c_str());
574        if (l.size()!=1)
575            return;
576
577        for (int i=0; i<l[0]->rowCount(); i++)
578        {
579            QStandardItem *row = l[0]->child(i);
580            if (row->text().toStdString()==service)
581            {
582                l[0]->removeRow(row->index().row());
583                return;
584            }
585        }
586    }
587
588    void handleRemoveAllServices(const std::string &server)
589    {
590        QStandardItemModel *m = 0;
591        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
592        {
593            QList<QStandardItem*> l = m->findItems(server.c_str());
594            if (l.size()==1)
595                m->removeRow(l[0]->index().row());
596        }
597
598        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
599        {
600            QList<QStandardItem*> l = m->findItems(server.c_str());
601            if (l.size()==1)
602                m->removeRow(l[0]->index().row());
603        }
604    }
605
606    void handleAddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
607    {
608        const bool iscmd = IsCommand(server, service)==true;
609
610        QStandardItem *item = AddServiceItem(server, service, iscmd);
611        AddDescription(item, vec);
612    }
613
614    // ======================================================================
615
616    void SubscribeService(const string &service)
617    {
618        if (fServices.find(service)!=fServices.end())
619        {
620            cout << "ERROR - We are already subscribed to " << service << endl;
621            return;
622        }
623
624        fServices[service] = new DimStampedInfo(service.c_str(), (void*)NULL, 0, this);
625    }
626
627    void UnsubscribeService(const string &service)
628    {
629        const map<string,DimInfo*>::iterator i=fServices.find(service);
630
631        if (i==fServices.end())
632        {
633            cout << "ERROR - We are not subscribed to " << service << endl;
634            return;
635        }
636
637        delete i->second;
638
639        fServices.erase(i);
640    }
641
642    void UnsubscribeServer(const string &server)
643    {
644        for (map<string,DimInfo*>::iterator i=fServices.begin();
645             i!=fServices.end(); i++)
646            if (i->first.substr(0, server.length()+1)==server+'/')
647            {
648                delete i->second;
649                fServices.erase(i);
650            }
651    }
652
653    void UnsubscribeAllServers()
654    {
655        for (map<string,DimInfo*>::iterator i=fServices.begin();
656             i!=fServices.end(); i++)
657            delete i->second;
658
659        fServices.clear();
660    }
661
662    // ======================================================================
663
664    struct DimData
665    {
666        Time time;
667        int  qos;
668        string name;
669        string format;
670        vector<char> data;
671
672        DimInfo *info;  // this is ONLY for a fast check of the type of the DimData!!
673
674        DimData(DimInfo *inf) :
675            qos(inf->getQuality()),
676            name(inf->getName()),
677            format(inf->getFormat()),
678            data(inf->getString(), inf->getString()+inf->getSize()),
679            info(inf)
680        {
681            // Must be called in exactly this order!
682            const int tsec = inf->getTimestamp();
683            const int tms  = inf->getTimestampMillisecs();
684
685            time = Time(tsec, tms*1000);
686        }
687
688        template<typename T>
689                T get() const { return *reinterpret_cast<const T*>(data.data()); }
690
691            vector<char> vec(int b) const { return vector<char>(data.begin()+b, data.end()); }
692            string str(unsigned int b) const { return b>=data.size()?string():string(data.data()+b, data.size()-b); }
693            const char *c_str() const { return (char*)data.data(); }
694
695            vector<boost::any> any() const
696            {
697                const Converter conv(format);
698                conv.Print();
699                return conv.GetAny(data.data(), data.size());
700            }
701            int size() const { return data.size(); }
702            const void *ptr() const { return data.data(); }
703    };
704
705    // ======================= DNS ==========================================
706
707    void handleDimDNS(const DimData &d)
708    {
709        const int version = d.get<unsigned int>();
710
711        ostringstream str;
712        str << "V" << version/100 << 'r' << version%100;
713
714        SetLedColor(fStatusDNSLed, version==0 ? kLedRed : kLedGreen, Time());
715
716        fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str());
717        fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established.");
718    }
719
720
721    // ======================= Logger =======================================
722
723    void handleLoggerStats(const DimData &d)
724    {
725        const bool connected = d.size()!=0;
726
727        fLoggerET->setEnabled(connected);
728        fLoggerRate->setEnabled(connected);
729        fLoggerWritten->setEnabled(connected);
730        fLoggerFreeSpace->setEnabled(connected);
731        fLoggerSpaceLeft->setEnabled(connected);
732
733        if (!connected)
734            return;
735
736        const uint64_t *vals = reinterpret_cast<const uint64_t*>(d.ptr());
737
738        const size_t written = vals[0];
739        const size_t space   = vals[1];
740        const size_t rate    = vals[2];
741
742        fLoggerFreeSpace->setSuffix(" MB");
743        fLoggerFreeSpace->setDecimals(0);
744        fLoggerFreeSpace->setValue(space*1e-6);
745
746        if (space>   1000000)  // > 1GB
747        {
748            fLoggerFreeSpace->setSuffix(" GB");
749            fLoggerFreeSpace->setDecimals(2);
750            fLoggerFreeSpace->setValue(space*1e-9);
751        }
752        if (space>=  3000000)  // >= 3GB
753        {
754            fLoggerFreeSpace->setSuffix(" GB");
755            fLoggerFreeSpace->setDecimals(1);
756            fLoggerFreeSpace->setValue(space*1e-9);
757        }
758        if (space>=100000000)  // >= 100GB
759        {
760            fLoggerFreeSpace->setSuffix(" GB");
761            fLoggerFreeSpace->setDecimals(0);
762            fLoggerFreeSpace->setValue(space*1e-9);
763        }
764
765        fLoggerET->setTime(QTime().addSecs(rate>0?space/rate:0));
766        fLoggerRate->setValue(rate*1e-3); // kB/s
767        fLoggerWritten->setValue(written*1e-6);
768
769        fLoggerRate->setSuffix(" kB/s");
770        fLoggerRate->setDecimals(2);
771        fLoggerRate->setValue(rate*1e-3);
772        if (rate>   2000)  // > 2kB/s
773        {
774            fLoggerRate->setSuffix(" kB/s");
775            fLoggerRate->setDecimals(1);
776            fLoggerRate->setValue(rate*1e-3);
777        }
778        if (rate>=100000)  // >100kB/s
779        {
780            fLoggerRate->setSuffix(" kB/s");
781            fLoggerRate->setDecimals(0);
782            fLoggerRate->setValue(rate*1e-3);
783        }
784        if (rate>=1000000)  // >100kB/s
785        {
786            fLoggerRate->setSuffix(" MB/s");
787            fLoggerRate->setDecimals(2);
788            fLoggerRate->setValue(rate*1e-6);
789        }
790        if (rate>=10000000)  // >1MB/s
791        {
792            fLoggerRate->setSuffix(" MB/s");
793            fLoggerRate->setDecimals(1);
794            fLoggerRate->setValue(rate*1e-6);
795        }
796        if (rate>=100000000)  // >10MB/s
797        {
798            fLoggerRate->setSuffix(" MB/s");
799            fLoggerRate->setDecimals(0);
800            fLoggerRate->setValue(rate*1e-6);
801        }
802
803        if (space/1000000>static_cast<size_t>(fLoggerSpaceLeft->maximum()))
804            fLoggerSpaceLeft->setValue(fLoggerSpaceLeft->maximum());  // GB
805        else
806            fLoggerSpaceLeft->setValue(space/1000000);  // MB
807    }
808
809    void handleLoggerFilenameNight(const DimData &d)
810    {
811        const bool connected = d.size()!=0;
812
813        fLoggerFilenameNight->setEnabled(connected);
814        if (!connected)
815            return;
816
817        fLoggerFilenameNight->setText(d.c_str()+4);
818
819        const uint32_t files = d.get<uint32_t>();
820
821        SetLedColor(fLoggerLedLog,  files&1 ? kLedGreen : kLedGray, d.time);
822        SetLedColor(fLoggerLedRep,  files&2 ? kLedGreen : kLedGray, d.time);
823        SetLedColor(fLoggerLedFits, files&4 ? kLedGreen : kLedGray, d.time);
824    }
825
826    void handleLoggerFilenameRun(const DimData &d)
827    {
828        const bool connected = d.size()!=0;
829
830        fLoggerFilenameRun->setEnabled(connected);
831        if (!connected)
832            return;
833
834        fLoggerFilenameRun->setText(d.c_str()+4);
835
836        const uint32_t files = d.get<uint32_t>();
837
838        SetLedColor(fLoggerLedLog,  files&1 ? kLedGreen : kLedGray, d.time);
839        SetLedColor(fLoggerLedRep,  files&2 ? kLedGreen : kLedGray, d.time);
840        SetLedColor(fLoggerLedFits, files&4 ? kLedGreen : kLedGray, d.time);
841    }
842
843    void handleLoggerNumSubs(const DimData &d)
844    {
845        const bool connected = d.size()!=0;
846
847        fLoggerSubscriptions->setEnabled(connected);
848        fLoggerOpenFiles->setEnabled(connected);
849        if (!connected)
850            return;
851
852        const uint32_t *vals = reinterpret_cast<const uint32_t*>(d.ptr());
853
854        fLoggerSubscriptions->setValue(vals[0]);
855        fLoggerOpenFiles->setValue(vals[1]);
856    }
857
858    // ===================== FAD ============================================
859
860    void handleFadPassport(const DimData &d)
861    {
862        if (d.size()==0)
863            return;
864
865        if (d.size()!=sizeof(FAD::DimPassport))
866        {
867            cout << "Size mismatch: " << d.size() << " " << sizeof(FAD::DimPassport) << endl;
868            return;
869        }
870
871        const FAD::DimPassport &sdata = *reinterpret_cast<const FAD::DimPassport*>(d.ptr());
872
873        stringstream str1;
874        str1 << hex << "0x" << setfill('0') << setw(16) << sdata.fDNA;
875
876        fFadVersion->setValue(sdata.fVersion);
877        fFadBoardId->setValue(sdata.fBoardId);
878        fFadDNA->setText(str1.str().c_str());
879    }
880
881    void handleFadTemperatures(const DimData &d)
882    {
883        if (d.size()==0)
884            return;
885
886        if (d.size()!=sizeof(FAD::DimTemperatures))
887        {
888            cout << "Size mismatch: " << d.size() << " " << sizeof(FAD::DimTemperatures) << endl;
889            return;
890        }
891
892        const FAD::DimTemperatures &sdata = *reinterpret_cast<const FAD::DimTemperatures*>(d.ptr());
893
894        fFadTemp0->setValue(sdata.fTempDrs[0]);
895        fFadTemp1->setValue(sdata.fTempDrs[1]);
896        fFadTemp2->setValue(sdata.fTempDrs[2]);
897        fFadTemp3->setValue(sdata.fTempDrs[3]);
898    }
899
900    void handleFadSetup(const DimData &d)
901    {
902        if (d.size()==0)
903            return;
904
905        if (d.size()!=sizeof(FAD::DimSetup))
906        {
907            cout << "Size mismatch: " << d.size() << " " << sizeof(FAD::DimSetup) << endl;
908            return;
909        }
910
911
912    }
913
914    // ===================== FTM ============================================
915
916    double fTimeStamp1;
917
918    void handleFtmTriggerCounter(const DimData &d)
919    {
920        if (d.size()==0)
921            return;
922
923        if (d.size()!=sizeof(FTM::DimTriggerCounter))
924        {
925            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimTriggerCounter) << endl;
926            return;
927        }
928
929        const FTM::DimTriggerCounter &sdata = *reinterpret_cast<const FTM::DimTriggerCounter*>(d.ptr());
930
931        fFtmTime->setText(QString::number(sdata.fTimeStamp/1000000., 'f', 6)+ " s");
932        fTriggerCounter->setText(QString::number(sdata.fTriggerCounter));
933
934        if (sdata.fTimeStamp>0)
935            fTriggerCounterRate->setValue(1000000.*sdata.fTriggerCounter/sdata.fTimeStamp);
936        else
937            fTriggerCounterRate->setValue(0);
938
939
940        // ----------------------------------------------
941#ifdef HAVE_ROOT
942
943        if (fTriggerCounter0<0)
944        {
945            fTriggerCounter0 = sdata.fTriggerCounter;
946            fTimeStamp1      = sdata.fTimeStamp;
947            return;
948        }
949
950        TCanvas *c = fFtmRateCanv->GetCanvas();
951
952        TH1 *h = (TH1*)c->FindObject("TimeFrame");
953
954        const double rate  = sdata.fTriggerCounter-fTriggerCounter0;
955        const double tdiff = sdata.fTimeStamp     -fTimeStamp1;
956
957        fTriggerCounter0   = sdata.fTriggerCounter;
958        fTimeStamp1        = sdata.fTimeStamp;
959
960        if (rate<0 && tdiff<=0)
961        {
962            fGraphFtmRate.Set(0);
963
964            const double tm = Time().RootTime();
965
966            h->SetBins(1, tm, tm+60);
967            h->GetXaxis()->SetTimeFormat("%M'%S\"");
968            h->GetXaxis()->SetTitle("Time");
969
970            c->Modified();
971            c->Update();
972            return;
973        }
974
975        if (rate<0)
976            return;
977
978        const double avgrate = sdata.fTimeStamp>0 ? double(sdata.fTriggerCounter)/sdata.fTimeStamp*1000000 : 1;
979
980        const double t1 = h->GetXaxis()->GetXmax();
981        const double t0 = h->GetXaxis()->GetXmin();
982
983        h->SetBins(h->GetNbinsX()+1, t0, t0+sdata.fTimeStamp/1000000.+1);
984        fGraphFtmRate.SetPoint(fGraphFtmRate.GetN(),
985                               t0+sdata.fTimeStamp/1000000., 1000000*rate/tdiff);
986
987        if (t1-t0>60)
988        {
989            h->GetXaxis()->SetTimeFormat("%Hh%M'");
990            h->GetXaxis()->SetTitle("Time");
991        }
992
993        h->SetMinimum(0);
994        h->SetMaximum(2*avgrate);
995
996        c->Modified();
997        c->Update();
998#endif
999        // ----------------------------------------------
1000    }
1001
1002    void handleFtmCounter(const DimData &d)
1003    {
1004        if (d.size()==0)
1005            return;
1006
1007        if (d.size()!=sizeof(uint32_t)*6)
1008        {
1009            cout << "Size mismatch: " << d.size() << " " << sizeof(uint32_t)*6 << endl;
1010            return;
1011        }
1012
1013        const uint32_t *sdata = reinterpret_cast<const uint32_t*>(d.ptr());
1014
1015        fFtmCounterH->setValue(sdata[0]);
1016        fFtmCounterS->setValue(sdata[1]);
1017        fFtmCounterD->setValue(sdata[2]);
1018        fFtmCounterF->setValue(sdata[3]);
1019        fFtmCounterE->setValue(sdata[4]);
1020        fFtmCounterR->setValue(sdata[5]);
1021    }
1022
1023    int64_t fTriggerCounter0;
1024    int64_t fTimeStamp0;
1025
1026    void handleFtmDynamicData(const DimData &d)
1027    {
1028        if (d.size()==0)
1029            return;
1030
1031        if (d.size()!=sizeof(FTM::DimDynamicData))
1032        {
1033            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimDynamicData) << endl;
1034            return;
1035        }
1036
1037        const FTM::DimDynamicData &sdata = *reinterpret_cast<const FTM::DimDynamicData*>(d.ptr());
1038
1039        fOnTime->setText(QString::number(sdata.fOnTimeCounter/1000000., 'f', 6)+" s");
1040
1041        if (sdata.fTimeStamp>0)
1042            fOnTimeRel->setValue(100.*sdata.fOnTimeCounter/sdata.fTimeStamp);
1043        else
1044            fOnTimeRel->setValue(0);
1045
1046        fFtmTemp0->setValue(sdata.fTempSensor[0]*0.1);
1047        fFtmTemp1->setValue(sdata.fTempSensor[1]*0.1);
1048        fFtmTemp2->setValue(sdata.fTempSensor[2]*0.1);
1049        fFtmTemp3->setValue(sdata.fTempSensor[3]*0.1);
1050
1051
1052#ifdef HAVE_ROOT
1053
1054        // ----------------------------------------------
1055/*
1056        TCanvas *c = fFtmTempCanv->GetCanvas();
1057
1058//        static int cntr = 0;
1059//        double_t tm = cntr++;//Time().RootTime();
1060
1061        double tm = d.time.RootTime();
1062
1063        TH1 *h = (TH1*)c->FindObject("TimeFrame");
1064        h->FindBin(tm);
1065
1066        fGraphFtmTemp[0].SetPoint(fGraphFtmTemp[0].GetN(), tm, sdata.fTempSensor[0]*0.1);
1067        fGraphFtmTemp[1].SetPoint(fGraphFtmTemp[1].GetN(), tm, sdata.fTempSensor[1]*0.1);
1068        fGraphFtmTemp[2].SetPoint(fGraphFtmTemp[2].GetN(), tm, sdata.fTempSensor[2]*0.1);
1069        fGraphFtmTemp[3].SetPoint(fGraphFtmTemp[3].GetN(), tm, sdata.fTempSensor[3]*0.1);
1070
1071        c->Modified();
1072        c->Update();
1073*/
1074        // ----------------------------------------------
1075
1076        if (fTimeStamp0<0)
1077        {
1078            fTimeStamp0 = sdata.fTimeStamp;
1079            return;
1080        }
1081
1082        TCanvas *c = fFtmRateCanv->GetCanvas();
1083
1084        TH1 *h = (TH1*)c->FindObject("TimeFrame");
1085
1086        const double tdiff = sdata.fTimeStamp-fTimeStamp0;
1087        fTimeStamp0 = sdata.fTimeStamp;
1088
1089        if (tdiff<0)
1090        {
1091            for (int i=0; i<160; i++)
1092                fGraphPatchRate[i].Set(0);
1093            for (int i=0; i<40; i++)
1094                fGraphBoardRate[i].Set(0);
1095
1096            return;
1097        }
1098
1099        //const double t1 = h->GetXaxis()->GetXmax();
1100        const double t0 = h->GetXaxis()->GetXmin();
1101
1102        for (int i=0; i<160; i++)
1103            fGraphPatchRate[i].SetPoint(fGraphPatchRate[i].GetN(),
1104                                       t0+sdata.fTimeStamp, float(sdata.fRatePatch[i])/fFtmStaticData.fPrescaling[i]/1000);
1105        for (int i=0; i<40; i++)
1106            fGraphBoardRate[i].SetPoint(fGraphBoardRate[i].GetN(),
1107                                       t0+sdata.fTimeStamp, float(sdata.fRateBoard[i])/fFtmStaticData.fPrescaling[i]/1000);
1108
1109        c->Modified();
1110        c->Update();
1111
1112        // ----------------------------------------------
1113
1114        if (fThresholdIdx->value()>=0)
1115            fPatchRate->setValue(sdata.fRatePatch[fThresholdIdx->value()]);
1116
1117        valarray<double> dat(0., 1440);
1118
1119        for (int i=0; i<1440; i++)
1120            dat[i] = sdata.fRatePatch[fPatch[i]];
1121
1122        c = fRatesCanv->GetCanvas();
1123        Camera *cam = (Camera*)c->FindObject("Camera");
1124
1125        cam->SetData(dat);
1126
1127        c->Modified();
1128        c->Update();
1129#endif
1130    }
1131
1132    void DisplayRates()
1133    {
1134#ifdef HAVE_ROOT
1135        TCanvas *c = fFtmRateCanv->GetCanvas();
1136
1137        while (c->FindObject("PatchRate"))
1138            c->GetListOfPrimitives()->Remove(c->FindObject("PatchRate"));
1139
1140        while (c->FindObject("BoardRate"))
1141            c->GetListOfPrimitives()->Remove(c->FindObject("BoardRate"));
1142
1143        if (fRatePatch1->value()>=0)
1144            fGraphPatchRate[fRatePatch1->value()].Draw("PL");
1145        if (fRatePatch2->value()>=0)
1146            fGraphPatchRate[fRatePatch2->value()].Draw("PL");
1147        if (fRateBoard1->value()>=0)
1148            fGraphBoardRate[fRateBoard1->value()].Draw("PL");
1149        if (fRateBoard2->value()>=0)
1150            fGraphBoardRate[fRateBoard2->value()].Draw("PL");
1151#endif
1152    }
1153
1154    void on_fRatePatch1_valueChanged(int)
1155    {
1156        DisplayRates();
1157    }
1158
1159    void on_fRatePatch2_valueChanged(int)
1160    {
1161        DisplayRates();
1162    }
1163
1164    void on_fRateBoard1_valueChanged(int)
1165    {
1166        DisplayRates();
1167    }
1168
1169    void on_fRateBoard2_valueChanged(int)
1170    {
1171        DisplayRates();
1172    }
1173
1174    FTM::DimStaticData fFtmStaticData;
1175
1176    void SetFtuLed(int idx, int counter, const Time &t)
1177    {
1178        if (counter==0 || counter>3)
1179            counter = 3;
1180
1181        if (counter<0)
1182            counter = 0;
1183
1184        const LedColor_t col[4] = { kLedGray, kLedGreen, kLedOrange, kLedRed };
1185
1186        SetLedColor(fFtuLED[idx], col[counter], t);
1187
1188        fFtuStatus[idx] = counter;
1189    }
1190
1191    void SetFtuStatusLed(const Time &t)
1192    {
1193        const int max = fFtuStatus.max();
1194
1195        switch (max)
1196        {
1197        case 0:
1198            SetLedColor(fStatusFTULed, kLedGray, t);
1199            fStatusFTULabel->setText("All disabled");
1200            fStatusFTULabel->setToolTip("All FTUs are disabled");
1201            break;
1202
1203        case 1:
1204            SetLedColor(fStatusFTULed, kLedGreen, t);
1205            fStatusFTULabel->setToolTip("Communication with FTU is smooth.");
1206            fStatusFTULabel->setText("ok");
1207            break;
1208
1209        case 2:
1210            SetLedColor(fStatusFTULed, kLedOrange, t);
1211            fStatusFTULabel->setText("Warning");
1212            fStatusFTULabel->setToolTip("At least one FTU didn't answer immediately");
1213            break;
1214
1215        case 3:
1216            SetLedColor(fStatusFTULed, kLedRed, t);
1217            fStatusFTULabel->setToolTip("At least one FTU didn't answer!");
1218            fStatusFTULabel->setText("ERROR");
1219            break;
1220        }
1221    }
1222
1223    void handleFtmStaticData(const DimData &d)
1224    {
1225        if (d.size()==0)
1226            return;
1227
1228        if (d.size()!=sizeof(FTM::DimStaticData))
1229        {
1230            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimStaticData) << endl;
1231            return;
1232        }
1233
1234        const FTM::DimStaticData &sdata = *reinterpret_cast<const FTM::DimStaticData*>(d.ptr());
1235
1236        fTriggerInterval->setValue(sdata.fTriggerInterval);
1237        fPhysicsCoincidence->setValue(sdata.fMultiplicityPhysics);
1238        fCalibCoincidence->setValue(sdata.fMultiplicityCalib);
1239        fPhysicsWindow->setValue(sdata.fWindowPhysics);
1240        fCalibWindow->setValue(sdata.fWindowCalib);
1241
1242        fTriggerDelay->setValue(sdata.fDelayTrigger);
1243        fTimeMarkerDelay->setValue(sdata.fDelayTimeMarker);
1244        fDeadTime->setValue(sdata.fDeadTime);
1245
1246        fClockCondR0->setValue(sdata.fClockConditioner[0]);
1247        fClockCondR1->setValue(sdata.fClockConditioner[1]);
1248        fClockCondR8->setValue(sdata.fClockConditioner[2]);
1249        fClockCondR9->setValue(sdata.fClockConditioner[3]);
1250        fClockCondR11->setValue(sdata.fClockConditioner[4]);
1251        fClockCondR13->setValue(sdata.fClockConditioner[5]);
1252        fClockCondR14->setValue(sdata.fClockConditioner[6]);
1253        fClockCondR15->setValue(sdata.fClockConditioner[7]);
1254
1255        fTriggerSeqPed->setValue(sdata.fTriggerSeqPed);
1256        fTriggerSeqLPint->setValue(sdata.fTriggerSeqLPint);
1257        fTriggerSeqLPext->setValue(sdata.fTriggerSeqLPext);
1258
1259        fEnableTrigger->setChecked(sdata.HasTrigger());
1260        fEnableVeto->setChecked(sdata.HasVeto());
1261        fEnableExt1->setChecked(sdata.HasExt1());
1262        fEnableExt2->setChecked(sdata.HasExt2());
1263        fEnableClockCond->setChecked(sdata.HasClockConditioner());
1264
1265        for (int i=0; i<40; i++)
1266        {
1267            if (!sdata.IsActive(i))
1268                SetFtuLed(i, -1, d.time);
1269            else
1270            {
1271                if (fFtuStatus[i]==0)
1272                    SetFtuLed(i, 1, d.time);
1273            }
1274            fFtuLED[i]->setChecked(false);
1275        }
1276        SetFtuStatusLed(d.time);
1277
1278#ifdef HAVE_ROOT
1279        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1280        for (int i=0; i<1440; i++)
1281            cam->SetEnable(i, sdata.IsEnabled(i));
1282#endif
1283
1284        fPixelEnable->setChecked(sdata.IsEnabled(fPixelIdx->value()));
1285
1286        const int patch1 = fThresholdIdx->value();
1287        if (patch1>=0)
1288            fThresholdVal->setValue(sdata.fThreshold[patch1]);
1289
1290        fPrescalingVal->setValue(sdata.fPrescaling[0]);
1291
1292        fFtmStaticData = sdata;
1293    }
1294
1295    void handleFtmPassport(const DimData &d)
1296    {
1297        if (d.size()==0)
1298            return;
1299
1300        if (d.size()!=sizeof(FTM::DimPassport))
1301        {
1302            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimPassport) << endl;
1303            return;
1304        }
1305
1306        const FTM::DimPassport &sdata = *reinterpret_cast<const FTM::DimPassport*>(d.ptr());
1307
1308        stringstream str1, str2;
1309        str1 << hex << "0x" << setfill('0') << setw(16) << sdata.fBoardId;
1310        str2 << sdata.fFirmwareId;
1311
1312        fFtmBoardId->setText(str1.str().c_str());
1313        fFtmFirmwareId->setText(str2.str().c_str());
1314    }
1315
1316    void handleFtmFtuList(const DimData &d)
1317    {
1318        if (d.size()==0)
1319            return;
1320
1321        if (d.size()!=sizeof(FTM::DimFtuList))
1322        {
1323            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimFtuList) << endl;
1324            return;
1325        }
1326
1327        fPing->setChecked(false);
1328
1329        const FTM::DimFtuList &sdata = *reinterpret_cast<const FTM::DimFtuList*>(d.ptr());
1330
1331        stringstream str;
1332        str << "<table width='100%'>" << setfill('0');
1333        str << "<tr><th>Num</th><th></th><th>Addr</th><th></th><th>DNA</th></tr>";
1334        for (int i=0; i<40; i++)
1335        {
1336            str << "<tr>";
1337            str << "<td align='center'>"   << dec << i << hex << "</td>";
1338            str << "<td align='center'>:</td>";
1339            str << "<td align='center'>0x" << setw(2)  << (int)sdata.fAddr[i] << "</td>";
1340            str << "<td align='center'>:</td>";
1341            str << "<td align='center'>0x" << setw(16) << sdata.fDNA[i] << "</td>";
1342            str << "</tr>";
1343        }
1344        str << "</table>";
1345
1346        fFtuDNA->setText(str.str().c_str());
1347
1348        fFtuAnswersTotal->setValue(sdata.fNumBoards);
1349        fFtuAnswersCrate0->setValue(sdata.fNumBoardsCrate[0]);
1350        fFtuAnswersCrate1->setValue(sdata.fNumBoardsCrate[1]);
1351        fFtuAnswersCrate2->setValue(sdata.fNumBoardsCrate[2]);
1352        fFtuAnswersCrate3->setValue(sdata.fNumBoardsCrate[3]);
1353
1354        for (int i=0; i<40; i++)
1355            SetFtuLed(i, sdata.IsActive(i) ? sdata.fPing[i] : -1, d.time);
1356
1357        SetFtuStatusLed(d.time);
1358    }
1359
1360    void handleFtmError(const DimData &d)
1361    {
1362        if (d.size()==0)
1363            return;
1364
1365        const FTM::DimError &sdata = *reinterpret_cast<const FTM::DimError*>(d.ptr());
1366
1367        SetFtuLed(sdata.fError.fDestAddress , sdata.fError.fNumCalls, d.time);
1368        SetFtuStatusLed(d.time);
1369
1370        // FIXME: Write to special window!
1371        //Out() << "Error:" << endl;
1372        //Out() << sdata.fError << endl;
1373    }
1374
1375    // ====================== MessageImp ====================================
1376
1377    bool fChatOnline;
1378
1379    void handleStateChanged(const Time &time, const std::string &server,
1380                            const State &s)
1381    {
1382        // FIXME: Prefix tooltip with time
1383        if (server=="FTM_CONTROL")
1384        {
1385            fStatusFTMLabel->setText(s.name.c_str());
1386            fStatusFTMLabel->setToolTip(s.comment.c_str());
1387
1388            bool enable = false;
1389
1390            if (s.index<FTM::kDisconnected) // No Dim connection
1391                SetLedColor(fStatusFTMLed, kLedGray, time);
1392            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
1393                SetLedColor(fStatusFTMLed, kLedYellow, time);
1394            if (s.index==FTM::kConnected || s.index==FTM::kIdle || s.index==FTM::kTakingData) // Dim connection / FTM connected
1395                SetLedColor(fStatusFTMLed, kLedGreen, time);
1396
1397            if (s.index==FTM::kConnected || s.index==FTM::kIdle) // Dim connection / FTM connected
1398                enable = true;
1399
1400            fTriggerWidget->setEnabled(enable);
1401            fFtuWidget->setEnabled(enable);
1402            fRatesWidget->setEnabled(enable);
1403
1404            if (!enable)
1405            {
1406                SetLedColor(fStatusFTULed, kLedGray, time);
1407                fStatusFTULabel->setText("Offline");
1408                fStatusFTULabel->setToolTip("FTM is not online.");
1409            }
1410    }
1411
1412        if (server=="FAD_CONTROL")
1413        {
1414            fStatusFADLabel->setText(s.name.c_str());
1415            fStatusFADLabel->setToolTip(s.comment.c_str());
1416
1417            bool enable = false;
1418
1419            if (s.index<FAD::kDisconnected) // No Dim connection
1420                SetLedColor(fStatusFADLed, kLedGray, time);
1421            if (s.index==FAD::kDisconnected) // Dim connection / FTM disconnected
1422                SetLedColor(fStatusFADLed, kLedYellow, time);
1423            if (s.index==FAD::kConnected) // Dim connection / FTM connected
1424            {
1425                SetLedColor(fStatusFADLed, kLedGreen, time);
1426                enable = true;
1427            }
1428
1429            fFadWidget->setEnabled(enable);
1430        }
1431
1432        if (server=="DATA_LOGGER")
1433        {
1434            fStatusLoggerLabel->setText(s.name.c_str());
1435            fStatusLoggerLabel->setToolTip(s.comment.c_str());
1436
1437            bool enable = true;
1438
1439            if (s.index<=30)   // Ready/Waiting
1440                SetLedColor(fStatusLoggerLed, kLedYellow, time);
1441            if (s.index<-1)     // Offline
1442            {
1443                SetLedColor(fStatusLoggerLed, kLedGray, time);
1444                enable = false;
1445            }
1446            if (s.index>=0x100) // Error
1447                SetLedColor(fStatusLoggerLed, kLedRed, time);
1448            if (s.index==40)   // Logging
1449                SetLedColor(fStatusLoggerLed, kLedGreen, time);
1450
1451            fLoggerWidget->setEnabled(enable);
1452        }
1453
1454        if (server=="CHAT")
1455        {
1456            fStatusChatLabel->setText(s.name.c_str());
1457
1458            fChatOnline = s.index==0;
1459
1460            SetLedColor(fStatusChatLed, fChatOnline ? kLedGreen : kLedRed, time);
1461
1462            fChatSend->setEnabled(fChatOnline);
1463            fChatMessage->setEnabled(fChatOnline);
1464        }
1465
1466        if (server=="SCHEDULER")
1467        {
1468            fStatusSchedulerLabel->setText(s.name.c_str());
1469
1470            SetLedColor(fStatusSchedulerLed, s.index>=0 ? kLedGreen : kLedRed, time);
1471        }
1472    }
1473
1474    void handleStateOffline(const string &server)
1475    {
1476        handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM."));
1477    }
1478
1479    void on_fTabWidget_currentChanged(int which)
1480    {
1481        if (fTabWidget->tabText(which)=="Chat")
1482            fTabWidget->setTabIcon(which, QIcon());
1483    }
1484
1485    void handleWrite(const Time &time, const string &text, int qos)
1486    {
1487        stringstream out;
1488
1489        if (text.substr(0, 6)=="CHAT: ")
1490        {
1491            out << "<font size='-1' color='navy'>[<B>";
1492            out << Time::fmt("%H:%M:%S") << time << "</B>]</FONT>  ";
1493            out << text.substr(6);
1494            fChatText->append(out.str().c_str());
1495
1496            if (fTabWidget->tabText(fTabWidget->currentIndex())=="Chat")
1497                return;
1498
1499            static int num = 0;
1500            if (num++<2)
1501                return;
1502
1503            for (int i=0; i<fTabWidget->count(); i++)
1504                if (fTabWidget->tabText(i)=="Chat")
1505                {
1506                    fTabWidget->setTabIcon(i, QIcon(":/Resources/icons/warning 3.png"));
1507                    break;
1508                }
1509
1510            return;
1511        }
1512
1513
1514        out << "<font style='font-family:monospace' color='";
1515
1516        switch (qos)
1517        {
1518        case kMessage: out << "black";   break;
1519        case kInfo:    out << "green";   break;
1520        case kWarn:    out << "#FF6600"; break;
1521        case kError:   out << "maroon";  break;
1522        case kFatal:   out << "maroon";  break;
1523        case kDebug:   out << "navy";    break;
1524        default:       out << "navy";    break;
1525        }
1526        out << "'>" << time.GetAsStr() << " - " << text << "</font>";
1527
1528        fLogText->append(out.str().c_str());
1529
1530        if (qos>=kWarn)
1531            fTextEdit->append(out.str().c_str());
1532    }
1533
1534    void IndicateStateChange(const Time &time, const std::string &server)
1535    {
1536        const State s = GetState(server, GetCurrentState(server));
1537
1538        QApplication::postEvent(this,
1539           new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s)));
1540    }
1541
1542    int Write(const Time &time, const string &txt, int qos)
1543    {
1544        QApplication::postEvent(this,
1545           new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos)));
1546
1547        return 0;
1548    }
1549
1550    // ====================== Dim infoHandler================================
1551
1552    void handleDimService(const string &txt)
1553    {
1554        fDimSvcText->append(txt.c_str());
1555    }
1556
1557    void infoHandlerService(DimInfo &info)
1558    {
1559        const string fmt = string(info.getFormat()).empty() ? "C" : info.getFormat();
1560
1561        stringstream dummy;
1562        const Converter conv(dummy, fmt, false);
1563
1564        const Time tm(info.getTimestamp(), info.getTimestampMillisecs()*1000);
1565
1566        stringstream out;
1567        out << "<font size'-1' color='navy'>[" << Time::fmt("%H:%M:%S.%f") << tm << "]</font>   <B>" << info.getName() << "</B> - ";
1568
1569        bool iserr = true;
1570        if (!conv)
1571        {
1572            out << "Compilation of format string '" << fmt << "' failed!";
1573        }
1574        else
1575        {
1576            try
1577            {
1578                const string dat = conv.GetString(info.getData(), info.getSize());
1579                out << dat;
1580                iserr = false;
1581            }
1582            catch (const runtime_error &e)
1583            {
1584                out << "Conversion to string failed!<pre>" << e.what() << "</pre>";
1585            }
1586        }
1587
1588        // srand(hash<string>()(string(info.getName())));
1589        // int bg = rand()&0xffffff;
1590
1591        int bg = hash<string>()(string(info.getName()));
1592
1593        // allow only light colors
1594        bg = ~(bg&0x1f1f1f)&0xffffff;
1595
1596        if (iserr)
1597            bg = 0xffffff;
1598
1599        stringstream bgcol;
1600        bgcol << hex << setfill('0') << setw(6) << bg;
1601
1602        const string col = iserr ? "red" : "black";
1603        const string str = "<table width='100%' bgcolor=#"+bgcol.str()+"><tr><td><font color='"+col+"'>"+out.str()+"</font></td></tr></table>";
1604
1605        QApplication::postEvent(this,
1606                                new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str)));
1607    }
1608
1609    void CallInfoHandler(void (FactGui::*handler)(const DimData&), const DimData &d)
1610    {
1611        fInHandler = true;
1612        (this->*handler)(d);
1613        fInHandler = false;
1614    }
1615
1616    /*
1617    void CallInfoHandler(const boost::function<void()> &func)
1618    {
1619        // This ensures that newly received values are not sent back to the emitter
1620        // because changing the value emits the valueChanged signal (or similar)
1621        fInHandler = true;
1622        func();
1623        fInHandler = false;
1624    }*/
1625
1626    void PostInfoHandler(void (FactGui::*handler)(const DimData&))
1627    {
1628        //const boost::function<void()> f = boost::bind(handler, this, DimData(getInfo()));
1629
1630        FunctionEvent *evt = new FunctionEvent(boost::bind(&FactGui::CallInfoHandler, this, handler, DimData(getInfo())));
1631        // FunctionEvent *evt = new FunctionEvent(boost::bind(&FactGui::CallInfoHandler, this, f));
1632        // FunctionEvent *evt = new FunctionEvent(boost::bind(handler, this, DimData(getInfo()))));
1633
1634        QApplication::postEvent(this, evt);
1635    }
1636
1637    void infoHandler()
1638    {
1639        // Initialize the time-stamp (what a weird workaround...)
1640        if (getInfo())
1641            getInfo()->getTimestamp();
1642
1643        if (getInfo()==&fDimDNS)
1644            return PostInfoHandler(&FactGui::handleDimDNS);
1645
1646        cout << "HandleDimInfo " << getInfo()->getName() << endl;
1647
1648        if (getInfo()==&fDimLoggerStats)
1649            return PostInfoHandler(&FactGui::handleLoggerStats);
1650
1651        if (getInfo()==&fDimFadTemperatures)
1652            return PostInfoHandler(&FactGui::handleFadTemperatures);
1653
1654        if (getInfo()==&fDimFadSetup)
1655            return PostInfoHandler(&FactGui::handleFadSetup);
1656
1657        if (getInfo()==&fDimLoggerFilenameNight)
1658            return PostInfoHandler(&FactGui::handleLoggerFilenameNight);
1659
1660        if (getInfo()==&fDimLoggerNumSubs)
1661            return PostInfoHandler(&FactGui::handleLoggerNumSubs);
1662
1663        if (getInfo()==&fDimLoggerFilenameRun)
1664            return PostInfoHandler(&FactGui::handleLoggerFilenameRun);
1665
1666        if (getInfo()==&fDimFtmTriggerCounter)
1667            return PostInfoHandler(&FactGui::handleFtmTriggerCounter);
1668
1669        if (getInfo()==&fDimFtmCounter)
1670            return PostInfoHandler(&FactGui::handleFtmCounter);
1671
1672        if (getInfo()==&fDimFtmDynamicData)
1673            return PostInfoHandler(&FactGui::handleFtmDynamicData);
1674
1675        if (getInfo()==&fDimFtmPassport)
1676            return PostInfoHandler(&FactGui::handleFtmPassport);
1677
1678        if (getInfo()==&fDimFtmFtuList)
1679            return PostInfoHandler(&FactGui::handleFtmFtuList);
1680
1681        if (getInfo()==&fDimFtmStaticData)
1682            return PostInfoHandler(&FactGui::handleFtmStaticData);
1683
1684        if (getInfo()==&fDimFtmError)
1685            return PostInfoHandler(&FactGui::handleFtmError);
1686
1687        for (map<string,DimInfo*>::iterator i=fServices.begin(); i!=fServices.end(); i++)
1688            if (i->second==getInfo())
1689            {
1690                infoHandlerService(*i->second);
1691                return;
1692            }
1693
1694        DimNetwork::infoHandler();
1695    }
1696
1697
1698    // ======================================================================
1699
1700    bool event(QEvent *evt)
1701    {
1702        if (dynamic_cast<FunctionEvent*>(evt))
1703            return static_cast<FunctionEvent*>(evt)->Exec();
1704
1705        if (dynamic_cast<CheckBoxEvent*>(evt))
1706        {
1707            const QStandardItem &item = static_cast<CheckBoxEvent*>(evt)->item;
1708            const QStandardItem *par  = item.parent();
1709            if (par)
1710            {
1711                const QString server  = par->text();
1712                const QString service = item.text();
1713
1714                const string s = (server+'/'+service).toStdString();
1715
1716                if (item.checkState()==Qt::Checked)
1717                    SubscribeService(s);
1718                else
1719                    UnsubscribeService(s);
1720            }
1721        }
1722
1723        return MainWindow::event(evt); // unrecognized
1724    }
1725
1726    void on_fDimCmdSend_clicked()
1727    {
1728        const QString server    = fDimCmdServers->currentIndex().data().toString();
1729        const QString command   = fDimCmdCommands->currentIndex().data().toString();
1730        const QString arguments = fDimCmdLineEdit->displayText();
1731
1732        // FIXME: Sending a command exactly when the info Handler changes
1733        //        the list it might lead to confusion.
1734        try
1735        {
1736            SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString());
1737            fTextEdit->append("<font color='green'>Command '"+server+'/'+command+"' successfully emitted.</font>");
1738            fDimCmdLineEdit->clear();
1739        }
1740        catch (const runtime_error &e)
1741        {
1742            stringstream txt;
1743            txt << e.what();
1744
1745            string buffer;
1746            while (getline(txt, buffer, '\n'))
1747                fTextEdit->append(("<font color='red'><pre>"+buffer+"</pre></font>").c_str());
1748        }
1749    }
1750    void ChoosePatch(Camera &cam, int idx)
1751    {
1752        cam.Reset();
1753
1754        fThresholdIdx->setValue(idx);
1755
1756        //fThresholdVal->setEnabled(idx>=0);
1757        //fThresholdVolt->setEnabled(idx>=0);
1758        fPatchRate->setEnabled(idx>=0);
1759        if (idx<0)
1760            return;
1761
1762        fThresholdVal->setValue(fFtmStaticData.fThreshold[idx]);
1763        fPatchRate->setValue(cam.GetData(idx));
1764
1765        for (unsigned int i=0; i<fPatch.size(); i++)
1766            if (fPatch[i]==idx)
1767                cam.SetBold(i);
1768    }
1769
1770    void ChoosePixel(Camera &cam, int idx)
1771    {
1772        cam.SetWhite(idx);
1773        ChoosePatch(cam, fPatch[idx]);
1774
1775        fPixelEnable->setChecked(fFtmStaticData.IsEnabled(idx));
1776    }
1777
1778#ifdef HAVE_ROOT
1779    void slot_RootEventProcessed(TObject *obj, unsigned int evt, TCanvas *)
1780    {
1781        // kMousePressEvent       // TCanvas processed QEvent mousePressEvent
1782        // kMouseMoveEvent        // TCanvas processed QEvent mouseMoveEvent
1783        // kMouseReleaseEvent     // TCanvas processed QEvent mouseReleaseEvent
1784        // kMouseDoubleClickEvent // TCanvas processed QEvent mouseDoubleClickEvent
1785        // kKeyPressEvent         // TCanvas processed QEvent keyPressEvent
1786        // kEnterEvent            // TCanvas processed QEvent enterEvent
1787        // kLeaveEvent            // TCanvas processed QEvent leaveEvent
1788        if (dynamic_cast<TCanvas*>(obj))
1789            return;
1790
1791        TQtWidget *tipped = static_cast<TQtWidget*>(sender());
1792
1793        if (evt==11/*kMouseReleaseEvent*/)
1794        {
1795            if (dynamic_cast<Camera*>(obj))
1796            {
1797                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1798                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1799
1800                Camera *cam = static_cast<Camera*>(obj);
1801                const int idx = cam->GetIdx(xx, yy);
1802
1803                ChoosePixel(*cam, idx);
1804
1805                fPixelIdx->setValue(idx);
1806            }
1807            return;
1808        }
1809
1810        if (evt==61/*kMouseDoubleClickEvent*/)
1811        {
1812            if (dynamic_cast<Camera*>(obj))
1813            {
1814                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1815                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1816
1817                Camera *cam = static_cast<Camera*>(obj);
1818                const int idx = cam->GetIdx(xx, yy);
1819
1820                //cam->Toggle(idx);
1821
1822                Dim::SendCommand("FTM_CONTROL/TOGGLE_PIXEL", uint16_t(idx));
1823            }
1824            return;
1825        }
1826
1827        // Find the object which will get picked by the GetObjectInfo
1828        // due to buffer overflows in many root-versions
1829        // in TH1 and TProfile we have to work around and implement
1830        // our own GetObjectInfo which make everything a bit more
1831        // complicated.
1832#if ROOT_VERSION_CODE > ROOT_VERSION(5,22,00)
1833        const char *objectInfo =
1834            obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1835#else
1836        const char *objectInfo = dynamic_cast<TH1*>(obj) ?
1837            "" : obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1838#endif
1839
1840        QString tipText;
1841        tipText += obj->GetName();
1842        tipText += " [";
1843        tipText += obj->ClassName();
1844        tipText += "]: ";
1845        tipText += objectInfo;
1846
1847        if (dynamic_cast<Camera*>(obj))
1848        {
1849            const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1850            const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1851
1852            Camera *cam = static_cast<Camera*>(obj);
1853            int idx = fPatch[cam->GetIdx(xx, yy)];
1854
1855            tipText+="  Patch=";
1856            tipText+=QString::number(idx);
1857        }
1858
1859
1860        fStatusBar->showMessage(tipText, 3000);
1861
1862        gSystem->ProcessEvents();
1863        //QWhatsThis::display(tipText)
1864    }
1865
1866    void slot_RootUpdate()
1867    {
1868        gSystem->ProcessEvents();
1869        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
1870    }
1871
1872    void on_fThresholdIdx_valueChanged(int idx)
1873    {
1874        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1875        ChoosePatch(*cam, idx);
1876    }
1877
1878    void on_fPixelIdx_valueChanged(int idx)
1879    {
1880        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1881        ChoosePixel(*cam, idx);
1882    }
1883#endif
1884
1885    TGraph fGraphFtmTemp[4];
1886    TGraph fGraphFtmRate;
1887    TGraph fGraphPatchRate[160];
1888    TGraph fGraphBoardRate[40];
1889
1890    map<int, int> fPatch;
1891
1892#ifdef HAVE_ROOT
1893    void DrawTimeFrame(const char *ytitle)
1894    {
1895        const double tm = Time().RootTime();
1896
1897        TH1F h("TimeFrame", "", 1, tm, tm+60);//Time().RootTime()-1./24/60/60, Time().RootTime());
1898        h.SetDirectory(0);
1899//        h.SetBit(TH1::kCanRebin);
1900        h.SetStats(kFALSE);
1901//        h.SetMinimum(0);
1902//        h.SetMaximum(1);
1903        h.SetXTitle("Time");
1904        h.SetYTitle(ytitle);
1905        h.GetXaxis()->CenterTitle();
1906        h.GetYaxis()->CenterTitle();
1907        h.GetXaxis()->SetTimeDisplay(true);
1908        h.GetXaxis()->SetTimeFormat("%Mh%S'");
1909        h.GetXaxis()->SetLabelSize(0.025);
1910        h.GetYaxis()->SetLabelSize(0.025);
1911        h.GetYaxis()->SetTitleOffset(1.2);
1912//        h.GetYaxis()->SetTitleSize(1.2);
1913        h.DrawCopy()->SetDirectory(0);
1914    }
1915#endif
1916
1917public:
1918    FactGui() :
1919        fFtuStatus(40),
1920        fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this),
1921
1922        fDimLoggerStats        ("DATA_LOGGER/STATS", (void*)NULL, 0, this),
1923        fDimLoggerFilenameNight("DATA_LOGGER/FILENAME_NIGHTLY", const_cast<char*>(""), 0, this),
1924        fDimLoggerFilenameRun  ("DATA_LOGGER/FILENAME_RUN",     const_cast<char*>(""), 0, this),
1925        fDimLoggerNumSubs      ("DATA_LOGGER/NUM_SUBS",         const_cast<char*>(""), 0, this),
1926
1927        fDimFtmPassport      ("FTM_CONTROL/PASSPORT",        (void*)NULL, 0, this),
1928        fDimFtmTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", (void*)NULL, 0, this),
1929        fDimFtmError         ("FTM_CONTROL/ERROR",           (void*)NULL, 0, this),
1930        fDimFtmFtuList       ("FTM_CONTROL/FTU_LIST",        (void*)NULL, 0, this),
1931        fDimFtmStaticData    ("FTM_CONTROL/STATIC_DATA",     (void*)NULL, 0, this),
1932        fDimFtmDynamicData   ("FTM_CONTROL/DYNAMIC_DATA",    (void*)NULL, 0, this),
1933        fDimFtmCounter       ("FTM_CONTROL/COUNTER",         (void*)NULL, 0, this),
1934        fDimFadPassport      ("FAD_CONTROL/PASSPORT",        (void*)NULL, 0, this),
1935        fDimFadTemperatures  ("FAD_CONTROL/TEMPERATURES",    (void*)NULL, 0, this),
1936        fDimFadSetup         ("FAD_CONTROL/SETUP",           (void*)NULL, 0, this)
1937    {
1938        fTriggerWidget->setEnabled(false);
1939        fFtuWidget->setEnabled(false);
1940        fRatesWidget->setEnabled(false);
1941        fFadWidget->setEnabled(false);
1942        fLoggerWidget->setEnabled(false);
1943
1944        fChatSend->setEnabled(false);
1945        fChatMessage->setEnabled(false);
1946
1947        DimClient::sendCommand("CHAT/MSG", "GUI online.");
1948        // + MessageDimRX
1949
1950        // --------------------------------------------------------------------------
1951
1952        ifstream fin("fact-trigger-all.txt");
1953
1954        int l = 0;
1955
1956        string buf;
1957        while (getline(fin, buf, '\n'))
1958        {
1959            buf = Tools::Trim(buf);
1960            if (buf[0]=='#')
1961                continue;
1962
1963            stringstream str(buf);
1964            for (int i=0; i<9; i++)
1965            {
1966                int n;
1967                str >> n;
1968
1969                fPatch[n] = l;
1970            }
1971            l++;
1972        }
1973
1974        // --------------------------------------------------------------------------
1975#ifdef HAVE_ROOT
1976
1977        fGraphFtmRate.SetLineColor(kBlue);
1978        fGraphFtmRate.SetMarkerColor(kBlue);
1979        fGraphFtmRate.SetMarkerStyle(kFullDotMedium);
1980
1981        for (int i=0; i<160; i++)
1982        {
1983            fGraphPatchRate[i].SetName("PatchRate");
1984            fGraphPatchRate[i].SetLineColor(kBlue);
1985            fGraphPatchRate[i].SetMarkerColor(kBlue);
1986            fGraphPatchRate[i].SetMarkerStyle(kFullDotMedium);
1987        }
1988        for (int i=0; i<40; i++)
1989        {
1990            fGraphBoardRate[i].SetName("BoardRate");
1991            fGraphBoardRate[i].SetLineColor(kBlue);
1992            fGraphBoardRate[i].SetMarkerColor(kBlue);
1993            fGraphBoardRate[i].SetMarkerStyle(kFullDotMedium);
1994        }
1995        /*
1996        TCanvas *c = fFtmTempCanv->GetCanvas();
1997        c->SetBit(TCanvas::kNoContextMenu);
1998        c->SetBorderMode(0);
1999        c->SetFrameBorderMode(0);
2000        c->SetFillColor(kWhite);
2001        c->SetRightMargin(0.03);
2002        c->SetTopMargin(0.03);
2003        c->cd();
2004        */
2005        //CreateTimeFrame("Temperature / °C");
2006
2007        fGraphFtmTemp[0].SetMarkerStyle(kFullDotSmall);
2008        fGraphFtmTemp[1].SetMarkerStyle(kFullDotSmall);
2009        fGraphFtmTemp[2].SetMarkerStyle(kFullDotSmall);
2010        fGraphFtmTemp[3].SetMarkerStyle(kFullDotSmall);
2011
2012        fGraphFtmTemp[1].SetLineColor(kBlue);
2013        fGraphFtmTemp[2].SetLineColor(kRed);
2014        fGraphFtmTemp[3].SetLineColor(kGreen);
2015
2016        fGraphFtmTemp[1].SetMarkerColor(kBlue);
2017        fGraphFtmTemp[2].SetMarkerColor(kRed);
2018        fGraphFtmTemp[3].SetMarkerColor(kGreen);
2019
2020        //fGraphFtmTemp[0].Draw("LP");
2021        //fGraphFtmTemp[1].Draw("LP");
2022        //fGraphFtmTemp[2].Draw("LP");
2023        //fGraphFtmTemp[3].Draw("LP");
2024
2025        // --------------------------------------------------------------------------
2026
2027        TCanvas *c = fFtmRateCanv->GetCanvas();
2028        c->SetBit(TCanvas::kNoContextMenu);
2029        c->SetBorderMode(0);
2030        c->SetFrameBorderMode(0);
2031        c->SetFillColor(kWhite);
2032        c->SetRightMargin(0.03);
2033        c->SetTopMargin(0.03);
2034        c->SetGrid();
2035        c->cd();
2036
2037        DrawTimeFrame("Trigger rate [Hz]");
2038
2039        fTriggerCounter0 = -1;
2040
2041        fGraphFtmRate.SetMarkerStyle(kFullDotSmall);
2042        fGraphFtmRate.Draw("LP");
2043
2044        // --------------------------------------------------------------------------
2045
2046        c = fRatesCanv->GetCanvas();
2047        c->SetBit(TCanvas::kNoContextMenu);
2048        c->SetBorderMode(0);
2049        c->SetFrameBorderMode(0);
2050        c->SetFillColor(kWhite);
2051        c->cd();
2052
2053        Camera *cam = new Camera;
2054        cam->SetBit(kCanDelete);
2055        cam->Draw();
2056
2057        ChoosePixel(*cam, 1);
2058
2059//        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
2060
2061        //widget->setMouseTracking(true);
2062        //widget->EnableSignalEvents(kMouseMoveEvent);
2063
2064        fFtmRateCanv->setMouseTracking(true);
2065        fFtmRateCanv->EnableSignalEvents(kMouseMoveEvent);
2066
2067        fRatesCanv->setMouseTracking(true);
2068        fRatesCanv->EnableSignalEvents(kMouseMoveEvent|kMouseReleaseEvent|kMouseDoubleClickEvent);
2069
2070        connect(fRatesCanv,   SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
2071                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
2072        connect(fFtmRateCanv, SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
2073                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
2074#endif
2075    }
2076
2077    ~FactGui()
2078    {
2079        UnsubscribeAllServers();
2080    }
2081};
2082
2083#endif
Note: See TracBrowser for help on using the repository browser.