1//IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
2
3// By downloading, copying, installing or using the software you agree to this license.
4// If you do not agree to this license, do not download, install,
5// copy or use the software.
6
7
8//                          License Agreement
9//               For Open Source Computer Vision Library
10
11//Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
12//Copyright (C) 2008-2010, Willow Garage Inc., all rights reserved.
13//Third party copyrights are property of their respective owners.
14
15//Redistribution and use in source and binary forms, with or without modification,
16//are permitted provided that the following conditions are met:
17
18//  * Redistribution's of source code must retain the above copyright notice,
19//  this list of conditions and the following disclaimer.
20
21//  * Redistribution's in binary form must reproduce the above copyright notice,
22//  this list of conditions and the following disclaimer in the documentation
23//  and/or other materials provided with the distribution.
24
25//  * The name of the copyright holders may not be used to endorse or promote products
26//  derived from this software without specific prior written permission.
27
28//This software is provided by the copyright holders and contributors "as is" and
29//any express or implied warranties, including, but not limited to, the implied
30//warranties of merchantability and fitness for a particular purpose are disclaimed.
31//In no event shall the Intel Corporation or contributors be liable for any direct,
32//indirect, incidental, special, exemplary, or consequential damages
33//(including, but not limited to, procurement of substitute goods or services;
34//loss of use, data, or profits; or business interruption) however caused
35//and on any theory of liability, whether in contract, strict liability,
36//or tort (including negligence or otherwise) arising in any way out of
37//the use of this software, even if advised of the possibility of such damage.
38
39//--------------------Google Code 2010 -- Yannick Verdie--------------------//
40
41#include "precomp.hpp"
42
43#if defined(HAVE_QT)
44
45#include <memory>
46
47#include <window_QT.h>
48
49#include <math.h>
50
51#ifdef _WIN32
52#include <windows.h>
53#else
54#include <unistd.h>
55#endif
56
57#ifdef HAVE_QT_OPENGL
58    #ifdef Q_WS_X11
59        #include <GL/glx.h>
60    #endif
61#endif
62
63
64//Static and global first
65static GuiReceiver *guiMainThread = NULL;
66static int parameterSystemC = 1;
67static char* parameterSystemV[] = {(char*)""};
68static bool multiThreads = false;
69static int last_key = -1;
70QWaitCondition key_pressed;
71QMutex mutexKey;
72static const unsigned int threshold_zoom_img_region = 30;
73//the minimum zoom value to start displaying the values in the grid
74//that is also the number of pixel per grid
75
76static CvWinProperties* global_control_panel = NULL;
77//end static and global
78
79// Declaration
80Qt::ConnectionType autoBlockingConnection();
81
82// Implementation - this allows us to do blocking whilst automatically selecting the right
83// behaviour for in-thread and out-of-thread launches of cv windows. Qt strangely doesn't
84// cater for this, but does for strictly queued connections.
85Qt::ConnectionType autoBlockingConnection() {
86  return (QThread::currentThread() != QApplication::instance()->thread())
87      ? Qt::BlockingQueuedConnection
88      : Qt::DirectConnection;
89}
90
91CV_IMPL CvFont cvFontQt(const char* nameFont, int pointSize,CvScalar color,int weight,int style, int spacing)
92{
93    /*
94    //nameFont   <- only Qt
95    //CvScalar color   <- only Qt (blue_component, green_component, red\_component[, alpha_component])
96    int         font_face;//<- style in Qt
97    const int*  ascii;
98    const int*  greek;
99    const int*  cyrillic;
100    float       hscale, vscale;
101    float       shear;
102    int         thickness;//<- weight in Qt
103    float       dx;//spacing letter in Qt (0 default) in pixel
104    int         line_type;//<- pointSize in Qt
105    */
106    CvFont f = {nameFont,color,style,NULL,NULL,NULL,0,0,0,weight,spacing,pointSize};
107    return f;
108}
109
110
111CV_IMPL void cvAddText(const CvArr* img, const char* text, CvPoint org, CvFont* font)
112{
113    if (!guiMainThread)
114        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
115
116    QMetaObject::invokeMethod(guiMainThread,
117        "putText",
118        autoBlockingConnection(),
119        Q_ARG(void*, (void*) img),
120        Q_ARG(QString,QString::fromUtf8(text)),
121        Q_ARG(QPoint, QPoint(org.x,org.y)),
122        Q_ARG(void*,(void*) font));
123}
124
125
126double cvGetRatioWindow_QT(const char* name)
127{
128    if (!guiMainThread)
129        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
130
131    double result = -1;
132    QMetaObject::invokeMethod(guiMainThread,
133        "getRatioWindow",
134        autoBlockingConnection(),
135        Q_RETURN_ARG(double, result),
136        Q_ARG(QString, QString(name)));
137
138    return result;
139}
140
141
142void cvSetRatioWindow_QT(const char* name,double prop_value)
143{
144
145    if (!guiMainThread)
146        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
147
148    QMetaObject::invokeMethod(guiMainThread,
149        "setRatioWindow",
150        autoBlockingConnection(),
151        Q_ARG(QString, QString(name)),
152        Q_ARG(double, prop_value));
153}
154
155
156double cvGetPropWindow_QT(const char* name)
157{
158    if (!guiMainThread)
159        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
160
161    double result = -1;
162    QMetaObject::invokeMethod(guiMainThread,
163        "getPropWindow",
164        autoBlockingConnection(),
165        Q_RETURN_ARG(double, result),
166        Q_ARG(QString, QString(name)));
167
168    return result;
169}
170
171
172void cvSetPropWindow_QT(const char* name,double prop_value)
173{
174    if (!guiMainThread)
175        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
176
177    QMetaObject::invokeMethod(guiMainThread,
178        "setPropWindow",
179        autoBlockingConnection(),
180        Q_ARG(QString, QString(name)),
181        Q_ARG(double, prop_value));
182}
183
184void cv::setWindowTitle(const String& winname, const String& title)
185{
186    if (!guiMainThread)
187        CV_Error(Error::StsNullPtr, "NULL guiReceiver (please create a window)");
188
189    QMetaObject::invokeMethod(guiMainThread,
190        "setWindowTitle",
191        autoBlockingConnection(),
192        Q_ARG(QString, QString(winname.c_str())),
193        Q_ARG(QString, QString(title.c_str())));
194}
195
196
197void cvSetModeWindow_QT(const char* name, double prop_value)
198{
199    if (!guiMainThread)
200        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
201
202    QMetaObject::invokeMethod(guiMainThread,
203        "toggleFullScreen",
204        autoBlockingConnection(),
205        Q_ARG(QString, QString(name)),
206        Q_ARG(double, prop_value));
207}
208
209
210double cvGetModeWindow_QT(const char* name)
211{
212    if (!guiMainThread)
213        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
214
215    double result = -1;
216
217    QMetaObject::invokeMethod(guiMainThread,
218        "isFullScreen",
219        autoBlockingConnection(),
220        Q_RETURN_ARG(double, result),
221        Q_ARG(QString, QString(name)));
222
223    return result;
224}
225
226
227CV_IMPL void cvDisplayOverlay(const char* name, const char* text, int delayms)
228{
229    if (!guiMainThread)
230        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
231
232    QMetaObject::invokeMethod(guiMainThread,
233        "displayInfo",
234        autoBlockingConnection(),
235        Q_ARG(QString, QString(name)),
236        Q_ARG(QString, QString(text)),
237        Q_ARG(int, delayms));
238}
239
240
241CV_IMPL void cvSaveWindowParameters(const char* name)
242{
243    if (!guiMainThread)
244        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
245
246    QMetaObject::invokeMethod(guiMainThread,
247        "saveWindowParameters",
248        autoBlockingConnection(),
249        Q_ARG(QString, QString(name)));
250}
251
252
253CV_IMPL void cvLoadWindowParameters(const char* name)
254{
255    if (!guiMainThread)
256        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
257
258    QMetaObject::invokeMethod(guiMainThread,
259        "loadWindowParameters",
260        autoBlockingConnection(),
261        Q_ARG(QString, QString(name)));
262}
263
264
265CV_IMPL void cvDisplayStatusBar(const char* name, const char* text, int delayms)
266{
267    if (!guiMainThread)
268        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
269
270    QMetaObject::invokeMethod(guiMainThread,
271        "displayStatusBar",
272        autoBlockingConnection(),
273        Q_ARG(QString, QString(name)),
274        Q_ARG(QString, QString(text)),
275        Q_ARG(int, delayms));
276}
277
278
279CV_IMPL int cvWaitKey(int delay)
280{
281    int result = -1;
282
283    if (!guiMainThread)
284        return result;
285
286    unsigned long delayms = delay <= 0 ? ULONG_MAX : delay; //in milliseconds
287
288    if (multiThreads)
289    {
290        mutexKey.lock();
291        if (key_pressed.wait(&mutexKey, delayms)) //false if timeout
292        {
293            result = last_key;
294        }
295        last_key = -1;
296        mutexKey.unlock();
297    }
298    else
299    {
300        //cannot use wait here because events will not be distributed before processEvents (the main eventLoop is broken)
301        //so I create a Thread for the QTimer
302
303        if (delay > 0)
304            guiMainThread->timer->start(delay);
305
306        //QMutex dummy;
307
308        while (!guiMainThread->bTimeOut)
309        {
310            qApp->processEvents(QEventLoop::AllEvents);
311
312            if (!guiMainThread)//when all the windows are deleted
313                return result;
314
315            mutexKey.lock();
316            if (last_key != -1)
317            {
318                result = last_key;
319                last_key = -1;
320                guiMainThread->timer->stop();
321                //printf("keypressed\n");
322            }
323            mutexKey.unlock();
324
325            if (result!=-1)
326            {
327                break;
328            }
329            else
330            {
331                /*
332    * //will not work, I broke the event loop !!!!
333    dummy.lock();
334    QWaitCondition waitCondition;
335    waitCondition.wait(&dummy, 2);
336    */
337
338                //to decrease CPU usage
339                //sleep 1 millisecond
340#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
341                Sleep(1);
342#else
343                usleep(1000);
344#endif
345            }
346        }
347
348        guiMainThread->bTimeOut = false;
349    }
350    return result;
351}
352
353
354//Yannick Verdie
355//This function is experimental and some functions (such as cvSet/getWindowProperty will not work)
356//We recommend not using this function for now
357CV_IMPL int cvStartLoop(int (*pt2Func)(int argc, char *argv[]), int argc, char* argv[])
358{
359    multiThreads = true;
360    QFuture<int> future = QtConcurrent::run(pt2Func, argc, argv);
361    return guiMainThread->start();
362}
363
364
365CV_IMPL void cvStopLoop()
366{
367    qApp->exit();
368}
369
370
371static CvWindow* icvFindWindowByName(QString name)
372{
373    CvWindow* window = 0;
374
375    //This is not a very clean way to do the stuff. Indeed, QAction automatically generate toolTil (QLabel)
376    //that can be grabbed here and crash the code at 'w->param_name==name'.
377    foreach (QWidget* widget, QApplication::topLevelWidgets())
378    {
379        if (widget->isWindow() && !widget->parentWidget())//is a window without parent
380        {
381            CvWinModel* temp = (CvWinModel*) widget;
382
383            if (temp->type == type_CvWindow)
384            {
385                CvWindow* w = (CvWindow*) temp;
386                if (w->objectName() == name)
387                {
388                    window = w;
389                    break;
390                }
391            }
392        }
393    }
394
395    return window;
396}
397
398
399static CvBar* icvFindBarByName(QBoxLayout* layout, QString name_bar, typeBar type)
400{
401    if (!layout)
402        return NULL;
403
404    int stop_index = layout->layout()->count();
405
406    for (int i = 0; i < stop_index; ++i)
407    {
408        CvBar* t = (CvBar*) layout->layout()->itemAt(i);
409
410        if (t->type == type && t->name_bar == name_bar)
411            return t;
412    }
413
414    return NULL;
415}
416
417
418static CvTrackbar* icvFindTrackBarByName(const char* name_trackbar, const char* name_window, QBoxLayout* layout = NULL)
419{
420    QString nameQt(name_trackbar);
421    QString nameWinQt(name_window);
422
423    if (nameWinQt.isEmpty() && global_control_panel) //window name is null and we have a control panel
424        layout = global_control_panel->myLayout;
425
426    if (!layout)
427    {
428        QPointer<CvWindow> w = icvFindWindowByName(nameWinQt);
429
430        if (!w)
431            CV_Error(CV_StsNullPtr, "NULL window handler");
432
433        if (w->param_gui_mode == CV_GUI_NORMAL)
434            return (CvTrackbar*) icvFindBarByName(w->myBarLayout, nameQt, type_CvTrackbar);
435
436        if (w->param_gui_mode == CV_GUI_EXPANDED)
437        {
438            CvBar* result = icvFindBarByName(w->myBarLayout, nameQt, type_CvTrackbar);
439
440            if (result)
441                return (CvTrackbar*) result;
442
443            return (CvTrackbar*) icvFindBarByName(global_control_panel->myLayout, nameQt, type_CvTrackbar);
444        }
445
446        return NULL;
447    }
448    else
449    {
450        //layout was specified
451        return (CvTrackbar*) icvFindBarByName(layout, nameQt, type_CvTrackbar);
452    }
453}
454
455/*
456static CvButtonbar* icvFindButtonBarByName(const char* button_name, QBoxLayout* layout)
457{
458    QString nameQt(button_name);
459    return (CvButtonbar*) icvFindBarByName(layout, nameQt, type_CvButtonbar);
460}
461*/
462
463static int icvInitSystem(int* c, char** v)
464{
465    //"For any GUI application using Qt, there is precisely one QApplication object"
466    if (!QApplication::instance())
467    {
468        new QApplication(*c, v);
469        setlocale(LC_NUMERIC,"C");
470
471        qDebug() << "init done";
472
473#ifdef HAVE_QT_OPENGL
474        qDebug() << "opengl support available";
475#endif
476    }
477
478    return 0;
479}
480
481
482CV_IMPL int cvInitSystem(int, char**)
483{
484    icvInitSystem(&parameterSystemC, parameterSystemV);
485    return 0;
486}
487
488
489CV_IMPL int cvNamedWindow(const char* name, int flags)
490{
491    if (!guiMainThread)
492        guiMainThread = new GuiReceiver;
493    if (QThread::currentThread() != QApplication::instance()->thread()) {
494        multiThreads = true;
495        QMetaObject::invokeMethod(guiMainThread,
496        "createWindow",
497        Qt::BlockingQueuedConnection,  // block so that we can do useful stuff once we confirm it is created
498        Q_ARG(QString, QString(name)),
499        Q_ARG(int, flags));
500     } else {
501        guiMainThread->createWindow(QString(name), flags);
502     }
503
504    return 1; //Dummy value - probably should return the result of the invocation.
505}
506
507
508CV_IMPL void cvDestroyWindow(const char* name)
509{
510    if (!guiMainThread)
511        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
512
513    QMetaObject::invokeMethod(guiMainThread,
514        "destroyWindow",
515        Qt::AutoConnection,  // if another thread is controlling, let it handle it without blocking ourselves here
516        Q_ARG(QString, QString(name)));
517}
518
519
520CV_IMPL void cvDestroyAllWindows()
521{
522    if (!guiMainThread)
523        return;
524    QMetaObject::invokeMethod(guiMainThread,
525        "destroyAllWindow",
526        Qt::AutoConnection  // if another thread is controlling, let it handle it without blocking ourselves here
527        );
528}
529
530
531CV_IMPL void* cvGetWindowHandle(const char* name)
532{
533    if (!name)
534        CV_Error( CV_StsNullPtr, "NULL name string" );
535
536    return (void*) icvFindWindowByName(QLatin1String(name));
537}
538
539
540CV_IMPL const char* cvGetWindowName(void* window_handle)
541{
542    if( !window_handle )
543        CV_Error( CV_StsNullPtr, "NULL window handler" );
544
545    return ((CvWindow*)window_handle)->objectName().toLatin1().data();
546}
547
548
549CV_IMPL void cvMoveWindow(const char* name, int x, int y)
550{
551    if (!guiMainThread)
552        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
553    QMetaObject::invokeMethod(guiMainThread,
554        "moveWindow",
555        autoBlockingConnection(),
556        Q_ARG(QString, QString(name)),
557        Q_ARG(int, x),
558        Q_ARG(int, y));
559}
560
561CV_IMPL void cvResizeWindow(const char* name, int width, int height)
562{
563    if (!guiMainThread)
564        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
565    QMetaObject::invokeMethod(guiMainThread,
566        "resizeWindow",
567        autoBlockingConnection(),
568        Q_ARG(QString, QString(name)),
569        Q_ARG(int, width),
570        Q_ARG(int, height));
571}
572
573
574CV_IMPL int cvCreateTrackbar2(const char* name_bar, const char* window_name, int* val, int count, CvTrackbarCallback2 on_notify, void* userdata)
575{
576    if (!guiMainThread)
577        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
578
579    QMetaObject::invokeMethod(guiMainThread,
580        "addSlider2",
581        autoBlockingConnection(),
582        Q_ARG(QString, QString(name_bar)),
583        Q_ARG(QString, QString(window_name)),
584        Q_ARG(void*, (void*)val),
585        Q_ARG(int, count),
586        Q_ARG(void*, (void*)on_notify),
587        Q_ARG(void*, (void*)userdata));
588
589    return 1; //dummy value
590}
591
592
593CV_IMPL int cvStartWindowThread()
594{
595    return 0;
596}
597
598
599CV_IMPL int cvCreateTrackbar(const char* name_bar, const char* window_name, int* value, int count, CvTrackbarCallback on_change)
600{
601    if (!guiMainThread)
602        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
603
604    QMetaObject::invokeMethod(guiMainThread,
605        "addSlider",
606        autoBlockingConnection(),
607        Q_ARG(QString, QString(name_bar)),
608        Q_ARG(QString, QString(window_name)),
609        Q_ARG(void*, (void*)value),
610        Q_ARG(int, count),
611        Q_ARG(void*, (void*)on_change));
612
613    return 1; //dummy value
614}
615
616
617CV_IMPL int cvCreateButton(const char* button_name, CvButtonCallback on_change, void* userdata, int button_type, int initial_button_state)
618{
619    if (!guiMainThread)
620        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
621
622    if (initial_button_state < 0 || initial_button_state > 1)
623        return 0;
624
625    QMetaObject::invokeMethod(guiMainThread,
626        "addButton",
627        autoBlockingConnection(),
628        Q_ARG(QString, QString(button_name)),
629        Q_ARG(int,  button_type),
630        Q_ARG(int, initial_button_state),
631        Q_ARG(void*, (void*)on_change),
632        Q_ARG(void*, userdata));
633
634    return 1;//dummy value
635}
636
637
638CV_IMPL int cvGetTrackbarPos(const char* name_bar, const char* window_name)
639{
640    int result = -1;
641
642    QPointer<CvTrackbar> t = icvFindTrackBarByName(name_bar, window_name);
643
644    if (t)
645        result = t->slider->value();
646
647    return result;
648}
649
650
651CV_IMPL void cvSetTrackbarPos(const char* name_bar, const char* window_name, int pos)
652{
653    QPointer<CvTrackbar> t = icvFindTrackBarByName(name_bar, window_name);
654
655    if (t)
656        t->slider->setValue(pos);
657}
658
659
660CV_IMPL void cvSetTrackbarMax(const char* name_bar, const char* window_name, int maxval)
661{
662    if (maxval >= 0)
663    {
664        QPointer<CvTrackbar> t = icvFindTrackBarByName(name_bar, window_name);
665        if (t)
666        {
667            t->slider->setMaximum(maxval);
668        }
669    }
670}
671
672
673/* assign callback for mouse events */
674CV_IMPL void cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param)
675{
676    QPointer<CvWindow> w = icvFindWindowByName(QLatin1String(window_name));
677
678    if (!w)
679        CV_Error(CV_StsNullPtr, "NULL window handler");
680
681    w->setMouseCallBack(on_mouse, param);
682
683}
684
685
686CV_IMPL void cvShowImage(const char* name, const CvArr* arr)
687{
688    if (!guiMainThread)
689        guiMainThread = new GuiReceiver;
690    if (QThread::currentThread() != QApplication::instance()->thread()) {
691        multiThreads = true;
692        QMetaObject::invokeMethod(guiMainThread,
693            "showImage",
694             autoBlockingConnection(),
695             Q_ARG(QString, QString(name)),
696             Q_ARG(void*, (void*)arr)
697        );
698     } else {
699        guiMainThread->showImage(QString(name), (void*)arr);
700     }
701}
702
703
704#ifdef HAVE_QT_OPENGL
705
706CV_IMPL void cvSetOpenGlDrawCallback(const char* window_name, CvOpenGlDrawCallback callback, void* userdata)
707{
708    if (!guiMainThread)
709        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
710
711    QMetaObject::invokeMethod(guiMainThread,
712        "setOpenGlDrawCallback",
713        autoBlockingConnection(),
714        Q_ARG(QString, QString(window_name)),
715        Q_ARG(void*, (void*)callback),
716        Q_ARG(void*, userdata));
717}
718
719
720CV_IMPL void cvSetOpenGlContext(const char* window_name)
721{
722    if (!guiMainThread)
723        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
724
725    QMetaObject::invokeMethod(guiMainThread,
726        "setOpenGlContext",
727        autoBlockingConnection(),
728        Q_ARG(QString, QString(window_name)));
729}
730
731
732CV_IMPL void cvUpdateWindow(const char* window_name)
733{
734    if (!guiMainThread)
735        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
736
737    QMetaObject::invokeMethod(guiMainThread,
738        "updateWindow",
739        autoBlockingConnection(),
740        Q_ARG(QString, QString(window_name)));
741}
742
743#endif
744
745
746double cvGetOpenGlProp_QT(const char* name)
747{
748    double result = -1;
749
750    if (guiMainThread)
751    {
752        QMetaObject::invokeMethod(guiMainThread,
753            "isOpenGl",
754            autoBlockingConnection(),
755            Q_RETURN_ARG(double, result),
756            Q_ARG(QString, QString(name)));
757    }
758
759    return result;
760}
761
762
763//////////////////////////////////////////////////////
764// GuiReceiver
765
766
767GuiReceiver::GuiReceiver() : bTimeOut(false), nb_windows(0)
768{
769    doesExternalQAppExist = (QApplication::instance() != 0);
770    icvInitSystem(&parameterSystemC, parameterSystemV);
771
772    timer = new QTimer(this);
773    QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timeOut()));
774    timer->setSingleShot(true);
775    if ( doesExternalQAppExist ) {
776        moveToThread(QApplication::instance()->thread());
777    }
778}
779
780
781void GuiReceiver::isLastWindow()
782{
783    if (--nb_windows <= 0)
784    {
785        delete guiMainThread;//delete global_control_panel too
786        guiMainThread = NULL;
787
788        if (!doesExternalQAppExist)
789        {
790            qApp->quit();
791        }
792    }
793}
794
795
796GuiReceiver::~GuiReceiver()
797{
798    if (global_control_panel)
799    {
800        delete global_control_panel;
801        global_control_panel = NULL;
802    }
803}
804
805
806void GuiReceiver::putText(void* arr, QString text, QPoint org, void* arg2)
807{
808    CV_Assert(arr);
809
810    CvMat* mat, stub;
811    mat = cvGetMat(arr, &stub);
812
813    int nbChannelOriginImage = cvGetElemType(mat);
814    if (nbChannelOriginImage != CV_8UC3) return; //for now, font works only with 8UC3
815
816    QImage qimg(mat->data.ptr, mat->cols, mat->rows, mat->step, QImage::Format_RGB888);
817
818    CvFont* font = (CvFont*)arg2;
819
820    QPainter qp(&qimg);
821    if (font)
822    {
823        QFont f(font->nameFont, font->line_type/*PointSize*/, font->thickness/*weight*/);
824        f.setStyle((QFont::Style) font->font_face/*style*/);
825        f.setLetterSpacing(QFont::AbsoluteSpacing, font->dx/*spacing*/);
826        //cvScalar(blue_component, green_component, red_component[, alpha_component])
827        //Qt map non-transparent to 0xFF and transparent to 0
828        //OpenCV scalar is the reverse, so 255-font->color.val[3]
829        qp.setPen(QColor(font->color.val[2], font->color.val[1], font->color.val[0], 255 - font->color.val[3]));
830        qp.setFont(f);
831    }
832    qp.drawText(org, text);
833    qp.end();
834}
835
836
837void GuiReceiver::saveWindowParameters(QString name)
838{
839    QPointer<CvWindow> w = icvFindWindowByName(name);
840
841    if (w)
842        w->writeSettings();
843}
844
845
846void GuiReceiver::loadWindowParameters(QString name)
847{
848    QPointer<CvWindow> w = icvFindWindowByName(name);
849
850    if (w)
851        w->readSettings();
852}
853
854
855double GuiReceiver::getRatioWindow(QString name)
856{
857    QPointer<CvWindow> w = icvFindWindowByName(name);
858
859    if (!w)
860        return -1;
861
862    return w->getRatio();
863}
864
865
866void GuiReceiver::setRatioWindow(QString name, double arg2)
867{
868    QPointer<CvWindow> w = icvFindWindowByName( name.toLatin1().data() );
869
870    if (!w)
871        return;
872
873    int flags = (int) arg2;
874
875    w->setRatio(flags);
876}
877
878
879double GuiReceiver::getPropWindow(QString name)
880{
881    QPointer<CvWindow> w = icvFindWindowByName(name);
882
883    if (!w)
884        return -1;
885
886    return (double) w->getPropWindow();
887}
888
889
890void GuiReceiver::setPropWindow(QString name, double arg2)
891{
892    QPointer<CvWindow> w = icvFindWindowByName(name);
893
894    if (!w)
895        return;
896
897    int flags = (int) arg2;
898
899    w->setPropWindow(flags);
900}
901
902void GuiReceiver::setWindowTitle(QString name, QString title)
903{
904    QPointer<CvWindow> w = icvFindWindowByName(name);
905
906    if (!w)
907    {
908        cvNamedWindow(name.toLatin1().data());
909        w = icvFindWindowByName(name);
910    }
911
912    if (!w)
913        return;
914
915    w->setWindowTitle(title);
916}
917
918
919double GuiReceiver::isFullScreen(QString name)
920{
921    QPointer<CvWindow> w = icvFindWindowByName(name);
922
923    if (!w)
924        return -1;
925
926    return w->isFullScreen() ? CV_WINDOW_FULLSCREEN : CV_WINDOW_NORMAL;
927}
928
929
930void GuiReceiver::toggleFullScreen(QString name, double arg2)
931{
932    QPointer<CvWindow> w = icvFindWindowByName(name);
933
934    if (!w)
935        return;
936
937    int flags = (int) arg2;
938
939    w->toggleFullScreen(flags);
940}
941
942
943void GuiReceiver::createWindow(QString name, int flags)
944{
945    if (!qApp)
946        CV_Error(CV_StsNullPtr, "NULL session handler" );
947
948    // Check the name in the storage
949    if (icvFindWindowByName(name.toLatin1().data()))
950    {
951        return;
952    }
953
954    nb_windows++;
955    new CvWindow(name, flags);
956}
957
958
959void GuiReceiver::timeOut()
960{
961    bTimeOut = true;
962}
963
964
965void GuiReceiver::displayInfo(QString name, QString text, int delayms)
966{
967    QPointer<CvWindow> w = icvFindWindowByName(name);
968
969    if (w)
970        w->displayInfo(text, delayms);
971}
972
973
974void GuiReceiver::displayStatusBar(QString name, QString text, int delayms)
975{
976    QPointer<CvWindow> w = icvFindWindowByName(name);
977
978    if (w)
979        w->displayStatusBar(text, delayms);
980}
981
982
983void GuiReceiver::showImage(QString name, void* arr)
984{
985    QPointer<CvWindow> w = icvFindWindowByName(name);
986
987    if (!w) //as observed in the previous implementation (W32, GTK or Carbon), create a new window is the pointer returned is null
988    {
989        cvNamedWindow(name.toLatin1().data());
990        w = icvFindWindowByName(name);
991    }
992
993    if (!w || !arr)
994        return; // keep silence here.
995
996    if (w->isOpenGl())
997    {
998        CvMat* mat, stub;
999
1000        mat = cvGetMat(arr, &stub);
1001
1002        cv::Mat im = cv::cvarrToMat(mat);
1003        cv::imshow(name.toUtf8().data(), im);
1004    }
1005    else
1006    {
1007        w->updateImage(arr);
1008    }
1009
1010    if (w->isHidden())
1011        w->show();
1012}
1013
1014
1015void GuiReceiver::destroyWindow(QString name)
1016{
1017
1018    QPointer<CvWindow> w = icvFindWindowByName(name);
1019
1020    if (w)
1021    {
1022        w->close();
1023
1024        //in not-multiThreads mode, looks like the window is hidden but not deleted
1025        //so I do it manually
1026        //otherwise QApplication do it for me if the exec command was executed (in multiThread mode)
1027        if (!multiThreads)
1028            delete w;
1029    }
1030}
1031
1032
1033void GuiReceiver::destroyAllWindow()
1034{
1035    if (!qApp)
1036        CV_Error(CV_StsNullPtr, "NULL session handler" );
1037
1038    if (multiThreads)
1039    {
1040        // WARNING: this could even close windows from an external parent app
1041        //#TODO check externalQAppExists and in case it does, close windows carefully,
1042        //      i.e. apply the className-check from below...
1043        qApp->closeAllWindows();
1044    }
1045    else
1046    {
1047        bool isWidgetDeleted = true;
1048        while(isWidgetDeleted)
1049        {
1050            isWidgetDeleted = false;
1051            QWidgetList list = QApplication::topLevelWidgets();
1052            for (int i = 0; i < list.count(); i++)
1053            {
1054                QObject *obj = list.at(i);
1055                if (obj->metaObject()->className() == QString("CvWindow"))
1056                {
1057                    delete obj;
1058                    isWidgetDeleted = true;
1059                    break;
1060                }
1061            }
1062        }
1063    }
1064}
1065
1066
1067void GuiReceiver::moveWindow(QString name, int x, int y)
1068{
1069    QPointer<CvWindow> w = icvFindWindowByName(name);
1070
1071    if (w)
1072        w->move(x, y);
1073}
1074
1075
1076void GuiReceiver::resizeWindow(QString name, int width, int height)
1077{
1078    QPointer<CvWindow> w = icvFindWindowByName(name);
1079
1080    if (w)
1081    {
1082        w->showNormal();
1083        w->setViewportSize(QSize(width, height));
1084    }
1085}
1086
1087
1088void GuiReceiver::enablePropertiesButtonEachWindow()
1089{
1090    //For each window, enable window property button
1091    foreach (QWidget* widget, QApplication::topLevelWidgets())
1092    {
1093        if (widget->isWindow() && !widget->parentWidget()) //is a window without parent
1094        {
1095            CvWinModel* temp = (CvWinModel*) widget;
1096            if (temp->type == type_CvWindow)
1097            {
1098                CvWindow* w = (CvWindow*) widget;
1099
1100                //active window properties button
1101                w->enablePropertiesButton();
1102            }
1103        }
1104    }
1105}
1106
1107
1108void GuiReceiver::addButton(QString button_name, int button_type, int initial_button_state, void* on_change, void* userdata)
1109{
1110    if (!global_control_panel)
1111        return;
1112
1113    QPointer<CvButtonbar> b;
1114
1115    if (global_control_panel->myLayout->count() == 0) //if that is the first button attach to the control panel, create a new button bar
1116    {
1117        b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it
1118        enablePropertiesButtonEachWindow();
1119
1120    }
1121    else
1122    {
1123        CvBar* lastbar = (CvBar*) global_control_panel->myLayout->itemAt(global_control_panel->myLayout->count() - 1);
1124
1125        if (lastbar->type == type_CvTrackbar) //if last bar is a trackbar, create a new buttonbar, else, attach to the current bar
1126            b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it
1127        else
1128            b = (CvButtonbar*) lastbar;
1129
1130    }
1131
1132    b->addButton(button_name, (CvButtonCallback) on_change, userdata, button_type, initial_button_state);
1133}
1134
1135
1136void GuiReceiver::addSlider2(QString bar_name, QString window_name, void* value, int count, void* on_change, void *userdata)
1137{
1138    QBoxLayout *layout = NULL;
1139    QPointer<CvWindow> w;
1140
1141    if (!window_name.isEmpty())
1142    {
1143        w = icvFindWindowByName(window_name);
1144
1145        if (!w)
1146            return;
1147    }
1148    else
1149    {
1150        if (global_control_panel)
1151            layout = global_control_panel->myLayout;
1152    }
1153
1154    QPointer<CvTrackbar> t = icvFindTrackBarByName(bar_name.toLatin1().data(), window_name.toLatin1().data(), layout);
1155
1156    if (t) //trackbar exists
1157        return;
1158
1159    if (!value)
1160        CV_Error(CV_StsNullPtr, "NULL value pointer" );
1161
1162    if (count <= 0) //count is the max value of the slider, so must be bigger than 0
1163        CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" );
1164
1165    CvWindow::addSlider2(w, bar_name, (int*)value, count, (CvTrackbarCallback2) on_change, userdata);
1166}
1167
1168
1169void GuiReceiver::addSlider(QString bar_name, QString window_name, void* value, int count, void* on_change)
1170{
1171    QBoxLayout *layout = NULL;
1172    QPointer<CvWindow> w;
1173
1174    if (!window_name.isEmpty())
1175    {
1176        w = icvFindWindowByName(window_name);
1177
1178        if (!w)
1179            return;
1180    }
1181    else
1182    {
1183        if (global_control_panel)
1184            layout = global_control_panel->myLayout;
1185    }
1186
1187    QPointer<CvTrackbar> t = icvFindTrackBarByName(bar_name.toLatin1().data(), window_name.toLatin1().data(), layout);
1188
1189    if (t) //trackbar exists
1190        return;
1191
1192    if (!value)
1193        CV_Error(CV_StsNullPtr, "NULL value pointer" );
1194
1195    if (count <= 0) //count is the max value of the slider, so must be bigger than 0
1196        CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" );
1197
1198    CvWindow::addSlider(w, bar_name, (int*)value, count, (CvTrackbarCallback) on_change);
1199}
1200
1201
1202int GuiReceiver::start()
1203{
1204    return qApp->exec();
1205}
1206
1207
1208void GuiReceiver::setOpenGlDrawCallback(QString name, void* callback, void* userdata)
1209{
1210    QPointer<CvWindow> w = icvFindWindowByName(name);
1211
1212    if (w)
1213        w->setOpenGlDrawCallback((CvOpenGlDrawCallback) callback, userdata);
1214}
1215
1216void GuiReceiver::setOpenGlContext(QString name)
1217{
1218    QPointer<CvWindow> w = icvFindWindowByName(name);
1219
1220    if (w)
1221        w->makeCurrentOpenGlContext();
1222}
1223
1224void GuiReceiver::updateWindow(QString name)
1225{
1226    QPointer<CvWindow> w = icvFindWindowByName(name);
1227
1228    if (w)
1229        w->updateGl();
1230}
1231
1232double GuiReceiver::isOpenGl(QString name)
1233{
1234    double result = -1;
1235
1236    QPointer<CvWindow> w = icvFindWindowByName(name);
1237
1238    if (w)
1239        result = (double) w->isOpenGl();
1240
1241    return result;
1242}
1243
1244
1245//////////////////////////////////////////////////////
1246// CvTrackbar
1247
1248
1249CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int _count, CvTrackbarCallback2 on_change, void* data)
1250{
1251    callback = NULL;
1252    callback2 = on_change;
1253    userdata = data;
1254
1255    create(arg, name, value, _count);
1256}
1257
1258
1259CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int _count, CvTrackbarCallback on_change)
1260{
1261    callback = on_change;
1262    callback2 = NULL;
1263    userdata = NULL;
1264
1265    create(arg, name, value, _count);
1266}
1267
1268
1269void CvTrackbar::create(CvWindow* arg, QString name, int* value, int _count)
1270{
1271    type = type_CvTrackbar;
1272    myparent = arg;
1273    name_bar = name;
1274    setObjectName(name_bar);
1275    dataSlider = value;
1276
1277    slider = new QSlider(Qt::Horizontal);
1278    slider->setFocusPolicy(Qt::StrongFocus);
1279    slider->setMinimum(0);
1280    slider->setMaximum(_count);
1281    slider->setPageStep(5);
1282    slider->setValue(*value);
1283    slider->setTickPosition(QSlider::TicksBelow);
1284
1285
1286    //Change style of the Slider
1287    //slider->setStyleSheet(str_Trackbar_css);
1288
1289    QFile qss(":/stylesheet-trackbar");
1290    if (qss.open(QFile::ReadOnly))
1291    {
1292        slider->setStyleSheet(QLatin1String(qss.readAll()));
1293        qss.close();
1294    }
1295
1296
1297    //this next line does not work if we change the style with a stylesheet, why ? (bug in QT ?)
1298    //slider->setTickPosition(QSlider::TicksBelow);
1299    label = new QPushButton;
1300    label->setFlat(true);
1301    setLabel(slider->value());
1302
1303
1304    QObject::connect(slider, SIGNAL(valueChanged(int)), this, SLOT(update(int)));
1305
1306    QObject::connect(label, SIGNAL(clicked()), this, SLOT(createDialog()));
1307
1308    //label->setStyleSheet("QPushButton:disabled {color: black}");
1309
1310    addWidget(label, Qt::AlignLeft);//name + value
1311    addWidget(slider, Qt::AlignCenter);//slider
1312}
1313
1314
1315void CvTrackbar::createDialog()
1316{
1317    bool ok = false;
1318
1319    //crash if I access the values directly and give them to QInputDialog, so do a copy first.
1320    int value = slider->value();
1321    int step = slider->singleStep();
1322    int min = slider->minimum();
1323    int max = slider->maximum();
1324
1325    int i =
1326#if QT_VERSION >= 0x040500
1327        QInputDialog::getInt
1328#else
1329        QInputDialog::getInteger
1330#endif
1331        (this->parentWidget(),
1332        tr("Slider %1").arg(name_bar),
1333        tr("New value:"),
1334        value,
1335        min,
1336        max,
1337        step,
1338        &ok);
1339
1340    if (ok)
1341        slider->setValue(i);
1342}
1343
1344
1345void CvTrackbar::update(int myvalue)
1346{
1347    setLabel(myvalue);
1348
1349    *dataSlider = myvalue;
1350    if (callback)
1351    {
1352        callback(myvalue);
1353        return;
1354    }
1355
1356    if (callback2)
1357    {
1358        callback2(myvalue, userdata);
1359        return;
1360    }
1361}
1362
1363
1364void CvTrackbar::setLabel(int myvalue)
1365{
1366    QString nameNormalized = name_bar.leftJustified( 10, ' ', true );
1367    QString valueMaximum = QString("%1").arg(slider->maximum());
1368    QString str = QString("%1 (%2/%3)").arg(nameNormalized).arg(myvalue,valueMaximum.length(),10,QChar('0')).arg(valueMaximum);
1369    label->setText(str);
1370}
1371
1372
1373//////////////////////////////////////////////////////
1374// CvButtonbar
1375
1376
1377//here CvButtonbar class
1378CvButtonbar::CvButtonbar(QWidget* arg,  QString arg2)
1379{
1380    type = type_CvButtonbar;
1381    myparent = arg;
1382    name_bar = arg2;
1383    setObjectName(name_bar);
1384
1385    group_button = new QButtonGroup(this);
1386}
1387
1388
1389void CvButtonbar::setLabel()
1390{
1391    QString nameNormalized = name_bar.leftJustified(10, ' ', true);
1392    label->setText(nameNormalized);
1393}
1394
1395
1396void CvButtonbar::addButton(QString name, CvButtonCallback call, void* userdata,  int button_type, int initial_button_state)
1397{
1398    QString button_name = name;
1399
1400    if (button_name == "")
1401        button_name = tr("button %1").arg(this->count());
1402
1403    QPointer<QAbstractButton> button;
1404
1405    if (button_type == CV_PUSH_BUTTON)
1406        button = (QAbstractButton*) new CvPushButton(this, button_name,call, userdata);
1407
1408    if (button_type == CV_CHECKBOX)
1409        button = (QAbstractButton*) new CvCheckBox(this, button_name,call, userdata, initial_button_state);
1410
1411    if (button_type == CV_RADIOBOX)
1412    {
1413        button = (QAbstractButton*) new CvRadioButton(this, button_name,call, userdata, initial_button_state);
1414        group_button->addButton(button);
1415    }
1416
1417    if (button)
1418    {
1419        if (button_type == CV_PUSH_BUTTON)
1420            QObject::connect(button, SIGNAL(clicked(bool)), button, SLOT(callCallBack(bool)));
1421        else
1422            QObject::connect(button, SIGNAL(toggled(bool)), button, SLOT(callCallBack(bool)));
1423
1424        addWidget(button, Qt::AlignCenter);
1425    }
1426}
1427
1428
1429//////////////////////////////////////////////////////
1430// Buttons
1431
1432
1433//buttons here
1434CvPushButton::CvPushButton(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4)
1435{
1436    myparent = arg1;
1437    button_name = arg2;
1438    callback = arg3;
1439    userdata = arg4;
1440
1441    setObjectName(button_name);
1442    setText(button_name);
1443
1444    if (isChecked())
1445        callCallBack(true);
1446}
1447
1448
1449void CvPushButton::callCallBack(bool checked)
1450{
1451    if (callback)
1452        callback(checked, userdata);
1453}
1454
1455
1456CvCheckBox::CvCheckBox(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4, int initial_button_state)
1457{
1458    myparent = arg1;
1459    button_name = arg2;
1460    callback = arg3;
1461    userdata = arg4;
1462
1463    setObjectName(button_name);
1464    setCheckState((initial_button_state == 1 ? Qt::Checked : Qt::Unchecked));
1465    setText(button_name);
1466
1467    if (isChecked())
1468        callCallBack(true);
1469}
1470
1471
1472void CvCheckBox::callCallBack(bool checked)
1473{
1474    if (callback)
1475        callback(checked, userdata);
1476}
1477
1478
1479CvRadioButton::CvRadioButton(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4, int initial_button_state)
1480{
1481    myparent = arg1;
1482    button_name = arg2;
1483    callback = arg3;
1484    userdata = arg4;
1485
1486    setObjectName(button_name);
1487    setChecked(initial_button_state);
1488    setText(button_name);
1489
1490    if (isChecked())
1491        callCallBack(true);
1492}
1493
1494void CvRadioButton::callCallBack(bool checked)
1495{
1496    if (callback)
1497        callback(checked, userdata);
1498}
1499
1500
1501//////////////////////////////////////////////////////
1502// CvWinProperties
1503
1504
1505//here CvWinProperties class
1506CvWinProperties::CvWinProperties(QString name_paraWindow, QObject* /*parent*/)
1507{
1508    //setParent(parent);
1509    type = type_CvWinProperties;
1510    setWindowFlags(Qt::Tool);
1511    setContentsMargins(0, 0, 0, 0);
1512    setWindowTitle(name_paraWindow);
1513    setObjectName(name_paraWindow);
1514    resize(100, 50);
1515
1516    myLayout = new QBoxLayout(QBoxLayout::TopToBottom);
1517    myLayout->setObjectName(QString::fromUtf8("boxLayout"));
1518    myLayout->setContentsMargins(0, 0, 0, 0);
1519    myLayout->setSpacing(0);
1520    myLayout->setMargin(0);
1521    myLayout->setSizeConstraint(QLayout::SetFixedSize);
1522    setLayout(myLayout);
1523
1524    hide();
1525}
1526
1527
1528void CvWinProperties::closeEvent(QCloseEvent* e)
1529{
1530    e->accept(); //intersept the close event (not sure I really need it)
1531    //an hide event is also sent. I will intercept it and do some processing
1532}
1533
1534
1535void CvWinProperties::showEvent(QShowEvent* evnt)
1536{
1537    //why -1,-1 ?: do this trick because the first time the code is run,
1538    //no value pos was saved so we let Qt move the window in the middle of its parent (event ignored).
1539    //then hide will save the last position and thus, we want to retreive it (event accepted).
1540    QPoint mypos(-1, -1);
1541    QSettings settings("OpenCV2", objectName());
1542    mypos = settings.value("pos", mypos).toPoint();
1543
1544    if (mypos.x() >= 0)
1545    {
1546        move(mypos);
1547        evnt->accept();
1548    }
1549    else
1550    {
1551        evnt->ignore();
1552    }
1553}
1554
1555
1556void CvWinProperties::hideEvent(QHideEvent* evnt)
1557{
1558    QSettings settings("OpenCV2", objectName());
1559    settings.setValue("pos", pos()); //there is an offset of 6 pixels (so the window's position is wrong -- why ?)
1560    evnt->accept();
1561}
1562
1563
1564CvWinProperties::~CvWinProperties()
1565{
1566    //clear the setting pos
1567    QSettings settings("OpenCV2", objectName());
1568    settings.remove("pos");
1569}
1570
1571
1572//////////////////////////////////////////////////////
1573// CvWindow
1574
1575
1576CvWindow::CvWindow(QString name, int arg2)
1577{
1578    type = type_CvWindow;
1579
1580    param_flags = arg2 & 0x0000000F;
1581    param_gui_mode = arg2 & 0x000000F0;
1582    param_ratio_mode =  arg2 & 0x00000F00;
1583
1584    //setAttribute(Qt::WA_DeleteOnClose); //in other case, does not release memory
1585    setContentsMargins(0, 0, 0, 0);
1586    setWindowTitle(name);
1587    setObjectName(name);
1588
1589    setFocus( Qt::PopupFocusReason ); //#1695 arrow keys are not received without the explicit focus
1590
1591    resize(400, 300);
1592    setMinimumSize(1, 1);
1593
1594    //1: create control panel
1595    if (!global_control_panel)
1596        global_control_panel = createParameterWindow();
1597
1598    //2: Layouts
1599    createBarLayout();
1600    createGlobalLayout();
1601
1602    //3: my view
1603#ifndef HAVE_QT_OPENGL
1604    if (arg2 & CV_WINDOW_OPENGL)
1605        CV_Error( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
1606    mode_display = CV_MODE_NORMAL;
1607#else
1608    mode_display = arg2 & CV_WINDOW_OPENGL ? CV_MODE_OPENGL : CV_MODE_NORMAL;
1609    if (mode_display == CV_MODE_OPENGL)
1610        param_gui_mode = CV_GUI_NORMAL;
1611#endif
1612    createView();
1613
1614    //4: shortcuts and actions
1615    //5: toolBar and statusbar
1616    if (param_gui_mode == CV_GUI_EXPANDED)
1617    {
1618        createActions();
1619        createShortcuts();
1620
1621        createToolBar();
1622        createStatusBar();
1623    }
1624
1625    //Now attach everything
1626    if (myToolBar)
1627        myGlobalLayout->addWidget(myToolBar, Qt::AlignCenter);
1628
1629    myGlobalLayout->addWidget(myView->getWidget(), Qt::AlignCenter);
1630
1631    myGlobalLayout->addLayout(myBarLayout, Qt::AlignCenter);
1632
1633    if (myStatusBar)
1634        myGlobalLayout->addWidget(myStatusBar, Qt::AlignCenter);
1635
1636    setLayout(myGlobalLayout);
1637    show();
1638}
1639
1640
1641CvWindow::~CvWindow()
1642{
1643    if (guiMainThread)
1644        guiMainThread->isLastWindow();
1645}
1646
1647
1648void CvWindow::setMouseCallBack(CvMouseCallback callback, void* param)
1649{
1650    myView->setMouseCallBack(callback, param);
1651}
1652
1653
1654void CvWindow::writeSettings()
1655{
1656    //organisation and application's name
1657    QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName());
1658
1659    settings.setValue("pos", pos());
1660    settings.setValue("size", size());
1661    settings.setValue("mode_resize" ,param_flags);
1662    settings.setValue("mode_gui", param_gui_mode);
1663
1664    myView->writeSettings(settings);
1665
1666    icvSaveTrackbars(&settings);
1667
1668    if (global_control_panel)
1669    {
1670        icvSaveControlPanel();
1671        settings.setValue("posPanel", global_control_panel->pos());
1672    }
1673}
1674
1675
1676
1677//TODO: load CV_GUI flag (done) and act accordingly (create win property if needed and attach trackbars)
1678void CvWindow::readSettings()
1679{
1680    //organisation and application's name
1681    QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName());
1682
1683    QPoint _pos = settings.value("pos", QPoint(200, 200)).toPoint();
1684    QSize _size = settings.value("size", QSize(400, 400)).toSize();
1685
1686    param_flags = settings.value("mode_resize", param_flags).toInt();
1687    param_gui_mode = settings.value("mode_gui", param_gui_mode).toInt();
1688
1689    param_flags = settings.value("mode_resize", param_flags).toInt();
1690
1691    myView->readSettings(settings);
1692
1693    //trackbar here
1694    icvLoadTrackbars(&settings);
1695
1696    resize(_size);
1697    move(_pos);
1698
1699    if (global_control_panel)
1700    {
1701        icvLoadControlPanel();
1702        global_control_panel->move(settings.value("posPanel", global_control_panel->pos()).toPoint());
1703    }
1704}
1705
1706
1707double CvWindow::getRatio()
1708{
1709    return myView->getRatio();
1710}
1711
1712
1713void CvWindow::setRatio(int flags)
1714{
1715    myView->setRatio(flags);
1716}
1717
1718
1719int CvWindow::getPropWindow()
1720{
1721    return param_flags;
1722}
1723
1724
1725void CvWindow::setPropWindow(int flags)
1726{
1727    if (param_flags == flags) //nothing to do
1728        return;
1729
1730    switch(flags)
1731    {
1732    case CV_WINDOW_NORMAL:
1733        myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
1734        param_flags = flags;
1735
1736        break;
1737
1738    case CV_WINDOW_AUTOSIZE:
1739        myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize);
1740        param_flags = flags;
1741
1742        break;
1743
1744    default:
1745        ;
1746    }
1747}
1748
1749void CvWindow::toggleFullScreen(int flags)
1750{
1751    if (isFullScreen() && flags == CV_WINDOW_NORMAL)
1752    {
1753        showTools();
1754        showNormal();
1755        return;
1756    }
1757
1758    if (!isFullScreen() && flags == CV_WINDOW_FULLSCREEN)
1759    {
1760        hideTools();
1761        showFullScreen();
1762        return;
1763    }
1764}
1765
1766
1767void CvWindow::updateImage(void* arr)
1768{
1769    myView->updateImage(arr);
1770}
1771
1772
1773void CvWindow::displayInfo(QString text, int delayms)
1774{
1775    myView->startDisplayInfo(text, delayms);
1776}
1777
1778
1779void CvWindow::displayStatusBar(QString text, int delayms)
1780{
1781    if (myStatusBar)
1782        myStatusBar->showMessage(text, delayms);
1783}
1784
1785
1786void CvWindow::enablePropertiesButton()
1787{
1788    if (!vect_QActions.empty())
1789        vect_QActions[9]->setDisabled(false);
1790}
1791
1792
1793CvButtonbar* CvWindow::createButtonBar(QString name_bar)
1794{
1795    QPointer<CvButtonbar> t = new CvButtonbar(global_control_panel, name_bar);
1796    t->setAlignment(Qt::AlignHCenter);
1797
1798    QPointer<QBoxLayout> myLayout = global_control_panel->myLayout;
1799
1800    myLayout->insertLayout(myLayout->count(), t);
1801
1802    return t;
1803}
1804
1805
1806void CvWindow::addSlider(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback on_change)
1807{
1808    QPointer<CvTrackbar> t = new CvTrackbar(w, name, value, count, on_change);
1809    t->setAlignment(Qt::AlignHCenter);
1810
1811    QPointer<QBoxLayout> myLayout;
1812
1813    if (w)
1814    {
1815        myLayout = w->myBarLayout;
1816    }
1817    else
1818    {
1819        myLayout = global_control_panel->myLayout;
1820
1821        //if first one, enable control panel
1822        if (myLayout->count() == 0)
1823            guiMainThread->enablePropertiesButtonEachWindow();
1824    }
1825
1826    myLayout->insertLayout(myLayout->count(), t);
1827}
1828
1829
1830void CvWindow::addSlider2(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback2 on_change, void* userdata)
1831{
1832    QPointer<CvTrackbar> t = new CvTrackbar(w, name, value, count, on_change, userdata);
1833    t->setAlignment(Qt::AlignHCenter);
1834
1835    QPointer<QBoxLayout> myLayout;
1836
1837    if (w)
1838    {
1839        myLayout = w->myBarLayout;
1840    }
1841    else
1842    {
1843        myLayout = global_control_panel->myLayout;
1844
1845        //if first one, enable control panel
1846        if (myLayout->count() == 0)
1847            guiMainThread->enablePropertiesButtonEachWindow();
1848    }
1849
1850    myLayout->insertLayout(myLayout->count(), t);
1851}
1852
1853
1854void CvWindow::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata)
1855{
1856    myView->setOpenGlDrawCallback(callback, userdata);
1857}
1858
1859
1860void CvWindow::makeCurrentOpenGlContext()
1861{
1862    myView->makeCurrentOpenGlContext();
1863}
1864
1865
1866void CvWindow::updateGl()
1867{
1868    myView->updateGl();
1869}
1870
1871
1872bool CvWindow::isOpenGl()
1873{
1874    return mode_display == CV_MODE_OPENGL;
1875}
1876
1877
1878void CvWindow::setViewportSize(QSize _size)
1879{
1880    resize(_size);
1881    myView->setSize(_size);
1882}
1883
1884
1885void CvWindow::createBarLayout()
1886{
1887    myBarLayout = new QBoxLayout(QBoxLayout::TopToBottom);
1888    myBarLayout->setObjectName(QString::fromUtf8("barLayout"));
1889    myBarLayout->setContentsMargins(0, 0, 0, 0);
1890    myBarLayout->setSpacing(0);
1891    myBarLayout->setMargin(0);
1892}
1893
1894
1895void CvWindow::createGlobalLayout()
1896{
1897    myGlobalLayout = new QBoxLayout(QBoxLayout::TopToBottom);
1898    myGlobalLayout->setObjectName(QString::fromUtf8("boxLayout"));
1899    myGlobalLayout->setContentsMargins(0, 0, 0, 0);
1900    myGlobalLayout->setSpacing(0);
1901    myGlobalLayout->setMargin(0);
1902    setMinimumSize(1, 1);
1903
1904    if (param_flags == CV_WINDOW_AUTOSIZE)
1905        myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize);
1906    else if (param_flags == CV_WINDOW_NORMAL)
1907        myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
1908}
1909
1910
1911void CvWindow::createView()
1912{
1913#ifdef HAVE_QT_OPENGL
1914    if (isOpenGl())
1915        myView = new OpenGlViewPort(this);
1916    else
1917#endif
1918        myView = new DefaultViewPort(this, param_ratio_mode);
1919}
1920
1921
1922void CvWindow::createActions()
1923{
1924    vect_QActions.resize(10);
1925
1926    QWidget* view = myView->getWidget();
1927
1928    //if the shortcuts are changed in window_QT.h, we need to update the tooltip manually
1929    vect_QActions[0] = new QAction(QIcon(":/left-icon"), "Panning left (CTRL+arrowLEFT)", this);
1930    vect_QActions[0]->setIconVisibleInMenu(true);
1931    QObject::connect(vect_QActions[0], SIGNAL(triggered()), view, SLOT(siftWindowOnLeft()));
1932
1933    vect_QActions[1] = new QAction(QIcon(":/right-icon"), "Panning right (CTRL+arrowRIGHT)", this);
1934    vect_QActions[1]->setIconVisibleInMenu(true);
1935    QObject::connect(vect_QActions[1], SIGNAL(triggered()), view, SLOT(siftWindowOnRight()));
1936
1937    vect_QActions[2] = new QAction(QIcon(":/up-icon"), "Panning up (CTRL+arrowUP)", this);
1938    vect_QActions[2]->setIconVisibleInMenu(true);
1939    QObject::connect(vect_QActions[2], SIGNAL(triggered()), view, SLOT(siftWindowOnUp()));
1940
1941    vect_QActions[3] = new QAction(QIcon(":/down-icon"), "Panning down (CTRL+arrowDOWN)", this);
1942    vect_QActions[3]->setIconVisibleInMenu(true);
1943    QObject::connect(vect_QActions[3], SIGNAL(triggered()), view, SLOT(siftWindowOnDown()) );
1944
1945    vect_QActions[4] = new QAction(QIcon(":/zoom_x1-icon"), "Zoom x1 (CTRL+P)", this);
1946    vect_QActions[4]->setIconVisibleInMenu(true);
1947    QObject::connect(vect_QActions[4], SIGNAL(triggered()), view, SLOT(resetZoom()));
1948
1949    vect_QActions[5] = new QAction(QIcon(":/imgRegion-icon"), tr("Zoom x%1 (see label) (CTRL+X)").arg(threshold_zoom_img_region), this);
1950    vect_QActions[5]->setIconVisibleInMenu(true);
1951    QObject::connect(vect_QActions[5], SIGNAL(triggered()), view, SLOT(imgRegion()));
1952
1953    vect_QActions[6] = new QAction(QIcon(":/zoom_in-icon"), "Zoom in (CTRL++)", this);
1954    vect_QActions[6]->setIconVisibleInMenu(true);
1955    QObject::connect(vect_QActions[6], SIGNAL(triggered()), view, SLOT(ZoomIn()));
1956
1957    vect_QActions[7] = new QAction(QIcon(":/zoom_out-icon"), "Zoom out (CTRL+-)", this);
1958    vect_QActions[7]->setIconVisibleInMenu(true);
1959    QObject::connect(vect_QActions[7], SIGNAL(triggered()), view, SLOT(ZoomOut()));
1960
1961    vect_QActions[8] = new QAction(QIcon(":/save-icon"), "Save current image (CTRL+S)", this);
1962    vect_QActions[8]->setIconVisibleInMenu(true);
1963    QObject::connect(vect_QActions[8], SIGNAL(triggered()), view, SLOT(saveView()));
1964
1965    vect_QActions[9] = new QAction(QIcon(":/properties-icon"), "Display properties window (CTRL+P)", this);
1966    vect_QActions[9]->setIconVisibleInMenu(true);
1967    QObject::connect(vect_QActions[9], SIGNAL(triggered()), this, SLOT(displayPropertiesWin()));
1968
1969    if (global_control_panel->myLayout->count() == 0)
1970        vect_QActions[9]->setDisabled(true);
1971}
1972
1973
1974void CvWindow::createShortcuts()
1975{
1976    vect_QShortcuts.resize(10);
1977
1978    QWidget* view = myView->getWidget();
1979
1980    vect_QShortcuts[0] = new QShortcut(shortcut_panning_left, this);
1981    QObject::connect(vect_QShortcuts[0], SIGNAL(activated()), view, SLOT(siftWindowOnLeft()));
1982
1983    vect_QShortcuts[1] = new QShortcut(shortcut_panning_right, this);
1984    QObject::connect(vect_QShortcuts[1], SIGNAL(activated()), view, SLOT(siftWindowOnRight()));
1985
1986    vect_QShortcuts[2] = new QShortcut(shortcut_panning_up, this);
1987    QObject::connect(vect_QShortcuts[2], SIGNAL(activated()), view, SLOT(siftWindowOnUp()));
1988
1989    vect_QShortcuts[3] = new QShortcut(shortcut_panning_down, this);
1990    QObject::connect(vect_QShortcuts[3], SIGNAL(activated()), view, SLOT(siftWindowOnDown()));
1991
1992    vect_QShortcuts[4] = new QShortcut(shortcut_zoom_normal, this);
1993    QObject::connect(vect_QShortcuts[4], SIGNAL(activated()), view, SLOT(resetZoom()));
1994
1995    vect_QShortcuts[5] = new QShortcut(shortcut_zoom_imgRegion, this);
1996    QObject::connect(vect_QShortcuts[5], SIGNAL(activated()), view, SLOT(imgRegion()));
1997
1998    vect_QShortcuts[6] = new QShortcut(shortcut_zoom_in, this);
1999    QObject::connect(vect_QShortcuts[6], SIGNAL(activated()), view, SLOT(ZoomIn()));
2000
2001    vect_QShortcuts[7] = new QShortcut(shortcut_zoom_out, this);
2002    QObject::connect(vect_QShortcuts[7], SIGNAL(activated()), view, SLOT(ZoomOut()));
2003
2004    vect_QShortcuts[8] = new QShortcut(shortcut_save_img, this);
2005    QObject::connect(vect_QShortcuts[8], SIGNAL(activated()), view, SLOT(saveView()));
2006
2007    vect_QShortcuts[9] = new QShortcut(shortcut_properties_win, this);
2008    QObject::connect(vect_QShortcuts[9], SIGNAL(activated()), this, SLOT(displayPropertiesWin()));
2009}
2010
2011
2012void CvWindow::createToolBar()
2013{
2014    myToolBar = new QToolBar(this);
2015    myToolBar->setFloatable(false); //is not a window
2016    myToolBar->setFixedHeight(28);
2017    myToolBar->setMinimumWidth(1);
2018
2019    foreach (QAction *a, vect_QActions)
2020        myToolBar->addAction(a);
2021}
2022
2023
2024void CvWindow::createStatusBar()
2025{
2026    myStatusBar = new QStatusBar(this);
2027    myStatusBar->setSizeGripEnabled(false);
2028    myStatusBar->setFixedHeight(20);
2029    myStatusBar->setMinimumWidth(1);
2030    myStatusBar_msg = new QLabel;
2031
2032    //I comment this because if we change the style, myview (the picture)
2033    //will not be the correct size anymore (will lost 2 pixel because of the borders)
2034
2035    //myStatusBar_msg->setFrameStyle(QFrame::Raised);
2036
2037    myStatusBar_msg->setAlignment(Qt::AlignHCenter);
2038    myStatusBar->addWidget(myStatusBar_msg);
2039}
2040
2041
2042void CvWindow::hideTools()
2043{
2044    if (myToolBar)
2045        myToolBar->hide();
2046
2047    if (myStatusBar)
2048        myStatusBar->hide();
2049
2050    if (global_control_panel)
2051        global_control_panel->hide();
2052}
2053
2054
2055void CvWindow::showTools()
2056{
2057    if (myToolBar)
2058        myToolBar->show();
2059
2060    if (myStatusBar)
2061        myStatusBar->show();
2062}
2063
2064
2065CvWinProperties* CvWindow::createParameterWindow()
2066{
2067    QString name_paraWindow = QFileInfo(QApplication::applicationFilePath()).fileName() + " settings";
2068
2069    CvWinProperties* result = new CvWinProperties(name_paraWindow, guiMainThread);
2070
2071    return result;
2072}
2073
2074
2075void CvWindow::displayPropertiesWin()
2076{
2077    if (global_control_panel->isHidden())
2078        global_control_panel->show();
2079    else
2080        global_control_panel->hide();
2081}
2082
2083
2084//Need more test here !
2085void CvWindow::keyPressEvent(QKeyEvent *evnt)
2086{
2087    //see http://doc.trolltech.com/4.6/qt.html#Key-enum
2088    int key = evnt->key();
2089
2090        Qt::Key qtkey = static_cast<Qt::Key>(key);
2091        char asciiCode = QTest::keyToAscii(qtkey);
2092        if (asciiCode != 0)
2093            key = static_cast<int>(asciiCode);
2094        else
2095            key = evnt->nativeVirtualKey(); //same codes as returned by GTK-based backend
2096
2097    //control plus (Z, +, -, up, down, left, right) are used for zoom/panning functions
2098        if (evnt->modifiers() != Qt::ControlModifier)
2099        {
2100        mutexKey.lock();
2101        last_key = key;
2102        mutexKey.unlock();
2103        key_pressed.wakeAll();
2104        //evnt->accept();
2105    }
2106
2107    QWidget::keyPressEvent(evnt);
2108}
2109
2110
2111void CvWindow::icvLoadControlPanel()
2112{
2113    QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName() + " control panel");
2114
2115    int bsize = settings.beginReadArray("bars");
2116
2117    if (bsize == global_control_panel->myLayout->layout()->count())
2118    {
2119        for (int i = 0; i < bsize; ++i)
2120        {
2121            CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i);
2122            settings.setArrayIndex(i);
2123            if (t->type == type_CvTrackbar)
2124            {
2125                if (t->name_bar == settings.value("namebar").toString())
2126                {
2127                    ((CvTrackbar*)t)->slider->setValue(settings.value("valuebar").toInt());
2128                }
2129            }
2130            if (t->type == type_CvButtonbar)
2131            {
2132                int subsize = settings.beginReadArray(QString("buttonbar")+i);
2133
2134                if ( subsize == ((CvButtonbar*)t)->layout()->count() )
2135                    icvLoadButtonbar((CvButtonbar*)t,&settings);
2136
2137                settings.endArray();
2138            }
2139        }
2140    }
2141
2142    settings.endArray();
2143}
2144
2145
2146void CvWindow::icvSaveControlPanel()
2147{
2148    QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()+" control panel");
2149
2150    settings.beginWriteArray("bars");
2151
2152    for (int i = 0; i < global_control_panel->myLayout->layout()->count(); ++i)
2153    {
2154        CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i);
2155        settings.setArrayIndex(i);
2156        if (t->type == type_CvTrackbar)
2157        {
2158            settings.setValue("namebar", QString(t->name_bar));
2159            settings.setValue("valuebar",((CvTrackbar*)t)->slider->value());
2160        }
2161        if (t->type == type_CvButtonbar)
2162        {
2163            settings.beginWriteArray(QString("buttonbar")+i);
2164            icvSaveButtonbar((CvButtonbar*)t,&settings);
2165            settings.endArray();
2166        }
2167    }
2168
2169    settings.endArray();
2170}
2171
2172
2173void CvWindow::icvSaveButtonbar(CvButtonbar* b, QSettings* settings)
2174{
2175    for (int i = 0, count = b->layout()->count(); i < count; ++i)
2176    {
2177        settings->setArrayIndex(i);
2178
2179        QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget();
2180        QString myclass(QLatin1String(temp->metaObject()->className()));
2181
2182        if (myclass == "CvPushButton")
2183        {
2184            CvPushButton* button = (CvPushButton*) temp;
2185            settings->setValue("namebutton", button->text());
2186            settings->setValue("valuebutton", int(button->isChecked()));
2187        }
2188        else if (myclass == "CvCheckBox")
2189        {
2190            CvCheckBox* button = (CvCheckBox*) temp;
2191            settings->setValue("namebutton", button->text());
2192            settings->setValue("valuebutton", int(button->isChecked()));
2193        }
2194        else if (myclass == "CvRadioButton")
2195        {
2196            CvRadioButton* button = (CvRadioButton*) temp;
2197            settings->setValue("namebutton", button->text());
2198            settings->setValue("valuebutton", int(button->isChecked()));
2199        }
2200    }
2201}
2202
2203
2204void CvWindow::icvLoadButtonbar(CvButtonbar* b, QSettings* settings)
2205{
2206    for (int i = 0, count = b->layout()->count(); i < count; ++i)
2207    {
2208        settings->setArrayIndex(i);
2209
2210        QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget();
2211        QString myclass(QLatin1String(temp->metaObject()->className()));
2212
2213        if (myclass == "CvPushButton")
2214        {
2215            CvPushButton* button = (CvPushButton*) temp;
2216
2217            if (button->text() == settings->value("namebutton").toString())
2218                button->setChecked(settings->value("valuebutton").toInt());
2219        }
2220        else if (myclass == "CvCheckBox")
2221        {
2222            CvCheckBox* button = (CvCheckBox*) temp;
2223
2224            if (button->text() == settings->value("namebutton").toString())
2225                button->setChecked(settings->value("valuebutton").toInt());
2226        }
2227        else if (myclass == "CvRadioButton")
2228        {
2229            CvRadioButton* button = (CvRadioButton*) temp;
2230
2231            if (button->text() == settings->value("namebutton").toString())
2232                button->setChecked(settings->value("valuebutton").toInt());
2233        }
2234
2235    }
2236}
2237
2238
2239void CvWindow::icvLoadTrackbars(QSettings* settings)
2240{
2241    int bsize = settings->beginReadArray("trackbars");
2242
2243    //trackbar are saved in the same order, so no need to use icvFindTrackbarByName
2244
2245    if (myBarLayout->layout()->count() == bsize) //if not the same number, the window saved and loaded is not the same (nb trackbar not equal)
2246    {
2247        for (int i = 0; i < bsize; ++i)
2248        {
2249            settings->setArrayIndex(i);
2250
2251            CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i);
2252
2253            if (t->name_bar == settings->value("name").toString())
2254                t->slider->setValue(settings->value("value").toInt());
2255
2256        }
2257    }
2258
2259    settings->endArray();
2260}
2261
2262
2263void CvWindow::icvSaveTrackbars(QSettings* settings)
2264{
2265    settings->beginWriteArray("trackbars");
2266
2267    for (int i = 0; i < myBarLayout->layout()->count(); ++i)
2268    {
2269        settings->setArrayIndex(i);
2270
2271        CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i);
2272
2273        settings->setValue("name", t->name_bar);
2274        settings->setValue("value", t->slider->value());
2275    }
2276
2277    settings->endArray();
2278}
2279
2280
2281//////////////////////////////////////////////////////
2282// DefaultViewPort
2283
2284
2285DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg), image2Draw_mat(0)
2286{
2287    centralWidget = arg;
2288    param_keepRatio = arg2;
2289
2290    setContentsMargins(0, 0, 0, 0);
2291    setMinimumSize(1, 1);
2292    setAlignment(Qt::AlignHCenter);
2293
2294    setObjectName(QString::fromUtf8("graphicsView"));
2295
2296    timerDisplay = new QTimer(this);
2297    timerDisplay->setSingleShot(true);
2298    connect(timerDisplay, SIGNAL(timeout()), this, SLOT(stopDisplayInfo()));
2299
2300    drawInfo = false;
2301    positionGrabbing = QPointF(0, 0);
2302    positionCorners = QRect(0, 0, size().width(), size().height());
2303
2304    on_mouse = 0;
2305    on_mouse_param = 0;
2306    mouseCoordinate = QPoint(-1, -1);
2307
2308    //no border
2309    setStyleSheet( "QGraphicsView { border-style: none; }" );
2310
2311    image2Draw_mat = cvCreateMat(viewport()->height(), viewport()->width(), CV_8UC3);
2312    cvZero(image2Draw_mat);
2313
2314    nbChannelOriginImage = 0;
2315
2316    setInteractive(false);
2317    setMouseTracking(true); //receive mouse event everytime
2318}
2319
2320
2321DefaultViewPort::~DefaultViewPort()
2322{
2323    if (image2Draw_mat)
2324        cvReleaseMat(&image2Draw_mat);
2325}
2326
2327
2328QWidget* DefaultViewPort::getWidget()
2329{
2330    return this;
2331}
2332
2333
2334void DefaultViewPort::setMouseCallBack(CvMouseCallback m, void* param)
2335{
2336    on_mouse = m;
2337
2338    on_mouse_param = param;
2339}
2340
2341void DefaultViewPort::writeSettings(QSettings& settings)
2342{
2343    settings.setValue("matrix_view.m11", param_matrixWorld.m11());
2344    settings.setValue("matrix_view.m12", param_matrixWorld.m12());
2345    settings.setValue("matrix_view.m13", param_matrixWorld.m13());
2346    settings.setValue("matrix_view.m21", param_matrixWorld.m21());
2347    settings.setValue("matrix_view.m22", param_matrixWorld.m22());
2348    settings.setValue("matrix_view.m23", param_matrixWorld.m23());
2349    settings.setValue("matrix_view.m31", param_matrixWorld.m31());
2350    settings.setValue("matrix_view.m32", param_matrixWorld.m32());
2351    settings.setValue("matrix_view.m33", param_matrixWorld.m33());
2352}
2353
2354
2355void DefaultViewPort::readSettings(QSettings& settings)
2356{
2357    qreal m11 = settings.value("matrix_view.m11", param_matrixWorld.m11()).toDouble();
2358    qreal m12 = settings.value("matrix_view.m12", param_matrixWorld.m12()).toDouble();
2359    qreal m13 = settings.value("matrix_view.m13", param_matrixWorld.m13()).toDouble();
2360    qreal m21 = settings.value("matrix_view.m21", param_matrixWorld.m21()).toDouble();
2361    qreal m22 = settings.value("matrix_view.m22", param_matrixWorld.m22()).toDouble();
2362    qreal m23 = settings.value("matrix_view.m23", param_matrixWorld.m23()).toDouble();
2363    qreal m31 = settings.value("matrix_view.m31", param_matrixWorld.m31()).toDouble();
2364    qreal m32 = settings.value("matrix_view.m32", param_matrixWorld.m32()).toDouble();
2365    qreal m33 = settings.value("matrix_view.m33", param_matrixWorld.m33()).toDouble();
2366
2367    param_matrixWorld = QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33);
2368}
2369
2370
2371double DefaultViewPort::getRatio()
2372{
2373    return param_keepRatio;
2374}
2375
2376
2377void DefaultViewPort::setRatio(int flags)
2378{
2379    if (getRatio() == flags) //nothing to do
2380        return;
2381
2382    //if valid flags
2383    if (flags == CV_WINDOW_FREERATIO || flags == CV_WINDOW_KEEPRATIO)
2384    {
2385        centralWidget->param_ratio_mode = flags;
2386        param_keepRatio = flags;
2387        updateGeometry();
2388        viewport()->update();
2389    }
2390}
2391
2392
2393void DefaultViewPort::updateImage(const CvArr* arr)
2394{
2395    CV_Assert(arr);
2396
2397    CvMat* mat, stub;
2398    int origin = 0;
2399
2400    if (CV_IS_IMAGE_HDR(arr))
2401        origin = ((IplImage*)arr)->origin;
2402
2403    mat = cvGetMat(arr, &stub);
2404
2405    if (!image2Draw_mat || !CV_ARE_SIZES_EQ(image2Draw_mat, mat))
2406    {
2407        if (image2Draw_mat)
2408            cvReleaseMat(&image2Draw_mat);
2409
2410        //the image in ipl (to do a deep copy with cvCvtColor)
2411        image2Draw_mat = cvCreateMat(mat->rows, mat->cols, CV_8UC3);
2412        image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows, image2Draw_mat->step, QImage::Format_RGB888);
2413
2414        //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent
2415        ratioX = width() / float(image2Draw_mat->cols);
2416        ratioY = height() / float(image2Draw_mat->rows);
2417        updateGeometry();
2418    }
2419
2420    nbChannelOriginImage = cvGetElemType(mat);
2421
2422    cvConvertImage(mat, image2Draw_mat, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB);
2423
2424    viewport()->update();
2425}
2426
2427
2428void DefaultViewPort::startDisplayInfo(QString text, int delayms)
2429{
2430    if (timerDisplay->isActive())
2431        stopDisplayInfo();
2432
2433    infoText = text;
2434    if (delayms > 0) timerDisplay->start(delayms);
2435    drawInfo = true;
2436}
2437
2438
2439void DefaultViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback /*callback*/, void* /*userdata*/)
2440{
2441    CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL");
2442}
2443
2444
2445void DefaultViewPort::makeCurrentOpenGlContext()
2446{
2447    CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL");
2448}
2449
2450
2451void DefaultViewPort::updateGl()
2452{
2453    CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL");
2454}
2455
2456
2457//Note: move 2 percent of the window
2458void DefaultViewPort::siftWindowOnLeft()
2459{
2460    float delta = 2 * width() / (100.0 * param_matrixWorld.m11());
2461    moveView(QPointF(delta, 0));
2462}
2463
2464
2465//Note: move 2 percent of the window
2466void DefaultViewPort::siftWindowOnRight()
2467{
2468    float delta = -2 * width() / (100.0 * param_matrixWorld.m11());
2469    moveView(QPointF(delta, 0));
2470}
2471
2472
2473//Note: move 2 percent of the window
2474void DefaultViewPort::siftWindowOnUp()
2475{
2476    float delta = 2 * height() / (100.0 * param_matrixWorld.m11());
2477    moveView(QPointF(0, delta));
2478}
2479
2480
2481//Note: move 2 percent of the window
2482void DefaultViewPort::siftWindowOnDown()
2483{
2484    float delta = -2 * height() / (100.0 * param_matrixWorld.m11());
2485    moveView(QPointF(0, delta));
2486}
2487
2488
2489void DefaultViewPort::imgRegion()
2490{
2491    scaleView((threshold_zoom_img_region / param_matrixWorld.m11() - 1) * 5, QPointF(size().width() / 2, size().height() / 2));
2492}
2493
2494
2495void DefaultViewPort::resetZoom()
2496{
2497    param_matrixWorld.reset();
2498    controlImagePosition();
2499}
2500
2501
2502void DefaultViewPort::ZoomIn()
2503{
2504    scaleView(0.5, QPointF(size().width() / 2, size().height() / 2));
2505}
2506
2507
2508void DefaultViewPort::ZoomOut()
2509{
2510    scaleView(-0.5, QPointF(size().width() / 2, size().height() / 2));
2511}
2512
2513
2514//can save as JPG, JPEG, BMP, PNG
2515void DefaultViewPort::saveView()
2516{
2517    QDate date_d = QDate::currentDate();
2518    QString date_s = date_d.toString("dd.MM.yyyy");
2519    QString name_s = centralWidget->windowTitle() + "_screenshot_" + date_s;
2520
2521    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File %1").arg(name_s), name_s + ".png", tr("Images (*.png *.jpg *.bmp *.jpeg)"));
2522
2523    if (!fileName.isEmpty()) //save the picture
2524    {
2525        QString extension = fileName.right(3);
2526
2527        // Create a new pixmap to render the viewport into
2528        QPixmap viewportPixmap(viewport()->size());
2529        viewport()->render(&viewportPixmap);
2530
2531        // Save it..
2532        if (QString::compare(extension, "png", Qt::CaseInsensitive) == 0)
2533        {
2534            viewportPixmap.save(fileName, "PNG");
2535            return;
2536        }
2537
2538        if (QString::compare(extension, "jpg", Qt::CaseInsensitive) == 0)
2539        {
2540            viewportPixmap.save(fileName, "JPG");
2541            return;
2542        }
2543
2544        if (QString::compare(extension, "bmp", Qt::CaseInsensitive) == 0)
2545        {
2546            viewportPixmap.save(fileName, "BMP");
2547            return;
2548        }
2549
2550        if (QString::compare(extension, "jpeg", Qt::CaseInsensitive) == 0)
2551        {
2552            viewportPixmap.save(fileName, "JPEG");
2553            return;
2554        }
2555
2556        CV_Error(CV_StsNullPtr, "file extension not recognized, please choose between JPG, JPEG, BMP or PNG");
2557    }
2558}
2559
2560
2561void DefaultViewPort::contextMenuEvent(QContextMenuEvent* evnt)
2562{
2563    if (centralWidget->vect_QActions.size() > 0)
2564    {
2565        QMenu menu(this);
2566
2567        foreach (QAction *a, centralWidget->vect_QActions)
2568            menu.addAction(a);
2569
2570        menu.exec(evnt->globalPos());
2571    }
2572}
2573
2574
2575void DefaultViewPort::resizeEvent(QResizeEvent* evnt)
2576{
2577    controlImagePosition();
2578
2579    //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent
2580    ratioX = width() / float(image2Draw_mat->cols);
2581    ratioY = height() / float(image2Draw_mat->rows);
2582
2583    if (param_keepRatio == CV_WINDOW_KEEPRATIO)//to keep the same aspect ratio
2584    {
2585        QSize newSize = QSize(image2Draw_mat->cols, image2Draw_mat->rows);
2586        newSize.scale(evnt->size(), Qt::KeepAspectRatio);
2587
2588        //imageWidth/imageHeight = newWidth/newHeight +/- epsilon
2589        //ratioX = ratioY +/- epsilon
2590        //||ratioX - ratioY|| = epsilon
2591        if (fabs(ratioX - ratioY) * 100 > ratioX) //avoid infinity loop / epsilon = 1% of ratioX
2592        {
2593            resize(newSize);
2594
2595            //move to the middle
2596            //newSize get the delta offset to place the picture in the middle of its parent
2597            newSize = (evnt->size() - newSize) / 2;
2598
2599            //if the toolbar is displayed, avoid drawing myview on top of it
2600            if (centralWidget->myToolBar)
2601                if(!centralWidget->myToolBar->isHidden())
2602                    newSize += QSize(0, centralWidget->myToolBar->height());
2603
2604            move(newSize.width(), newSize.height());
2605        }
2606    }
2607
2608    return QGraphicsView::resizeEvent(evnt);
2609}
2610
2611
2612void DefaultViewPort::wheelEvent(QWheelEvent* evnt)
2613{
2614    scaleView(evnt->delta() / 240.0, evnt->pos());
2615    viewport()->update();
2616}
2617
2618
2619void DefaultViewPort::mousePressEvent(QMouseEvent* evnt)
2620{
2621    int cv_event = -1, flags = 0;
2622    QPoint pt = evnt->pos();
2623
2624    //icvmouseHandler: pass parameters for cv_event, flags
2625    icvmouseHandler(evnt, mouse_down, cv_event, flags);
2626    icvmouseProcessing(QPointF(pt), cv_event, flags);
2627
2628    if (param_matrixWorld.m11()>1)
2629    {
2630        setCursor(Qt::ClosedHandCursor);
2631        positionGrabbing = evnt->pos();
2632    }
2633
2634    QWidget::mousePressEvent(evnt);
2635}
2636
2637
2638void DefaultViewPort::mouseReleaseEvent(QMouseEvent* evnt)
2639{
2640    int cv_event = -1, flags = 0;
2641    QPoint pt = evnt->pos();
2642
2643    //icvmouseHandler: pass parameters for cv_event, flags
2644    icvmouseHandler(evnt, mouse_up, cv_event, flags);
2645    icvmouseProcessing(QPointF(pt), cv_event, flags);
2646
2647    if (param_matrixWorld.m11()>1)
2648        setCursor(Qt::OpenHandCursor);
2649
2650    QWidget::mouseReleaseEvent(evnt);
2651}
2652
2653
2654void DefaultViewPort::mouseDoubleClickEvent(QMouseEvent* evnt)
2655{
2656    int cv_event = -1, flags = 0;
2657    QPoint pt = evnt->pos();
2658
2659    //icvmouseHandler: pass parameters for cv_event, flags
2660    icvmouseHandler(evnt, mouse_dbclick, cv_event, flags);
2661    icvmouseProcessing(QPointF(pt), cv_event, flags);
2662
2663    QWidget::mouseDoubleClickEvent(evnt);
2664}
2665
2666
2667void DefaultViewPort::mouseMoveEvent(QMouseEvent* evnt)
2668{
2669    int cv_event = CV_EVENT_MOUSEMOVE, flags = 0;
2670    QPoint pt = evnt->pos();
2671
2672    //icvmouseHandler: pass parameters for cv_event, flags
2673    icvmouseHandler(evnt, mouse_move, cv_event, flags);
2674    icvmouseProcessing(QPointF(pt), cv_event, flags);
2675
2676    if (param_matrixWorld.m11() > 1 && evnt->buttons() == Qt::LeftButton)
2677    {
2678        QPointF dxy = (pt - positionGrabbing)/param_matrixWorld.m11();
2679        positionGrabbing = evnt->pos();
2680        moveView(dxy);
2681    }
2682
2683    //I update the statusbar here because if the user does a cvWaitkey(0) (like with inpaint.cpp)
2684    //the status bar will only be repaint when a click occurs.
2685    if (centralWidget->myStatusBar)
2686        viewport()->update();
2687
2688    QWidget::mouseMoveEvent(evnt);
2689}
2690
2691
2692void DefaultViewPort::paintEvent(QPaintEvent* evnt)
2693{
2694    QPainter myPainter(viewport());
2695    myPainter.setWorldTransform(param_matrixWorld);
2696
2697    draw2D(&myPainter);
2698
2699    //Now disable matrixWorld for overlay display
2700    myPainter.setWorldMatrixEnabled(false);
2701
2702    //overlay pixel values if zoomed in far enough
2703    if (param_matrixWorld.m11()*ratioX >= threshold_zoom_img_region &&
2704        param_matrixWorld.m11()*ratioY >= threshold_zoom_img_region)
2705    {
2706        drawImgRegion(&myPainter);
2707    }
2708
2709    //in mode zoom/panning
2710    if (param_matrixWorld.m11() > 1)
2711    {
2712        drawViewOverview(&myPainter);
2713    }
2714
2715    //for information overlay
2716    if (drawInfo)
2717        drawInstructions(&myPainter);
2718
2719    //for statusbar
2720    if (centralWidget->myStatusBar)
2721        drawStatusBar();
2722
2723    QGraphicsView::paintEvent(evnt);
2724}
2725
2726
2727void DefaultViewPort::stopDisplayInfo()
2728{
2729    timerDisplay->stop();
2730    drawInfo = false;
2731}
2732
2733
2734inline bool DefaultViewPort::isSameSize(IplImage* img1, IplImage* img2)
2735{
2736    return img1->width == img2->width && img1->height == img2->height;
2737}
2738
2739
2740void DefaultViewPort::controlImagePosition()
2741{
2742    qreal left, top, right, bottom;
2743
2744    //after check top-left, bottom right corner to avoid getting "out" during zoom/panning
2745    param_matrixWorld.map(0,0,&left,&top);
2746
2747    if (left > 0)
2748    {
2749        param_matrixWorld.translate(-left,0);
2750        left = 0;
2751    }
2752    if (top > 0)
2753    {
2754        param_matrixWorld.translate(0,-top);
2755        top = 0;
2756    }
2757    //-------
2758
2759    QSize sizeImage = size();
2760    param_matrixWorld.map(sizeImage.width(),sizeImage.height(),&right,&bottom);
2761    if (right < sizeImage.width())
2762    {
2763        param_matrixWorld.translate(sizeImage.width()-right,0);
2764        right = sizeImage.width();
2765    }
2766    if (bottom < sizeImage.height())
2767    {
2768        param_matrixWorld.translate(0,sizeImage.height()-bottom);
2769        bottom = sizeImage.height();
2770    }
2771
2772    //save corner position
2773    positionCorners.setTopLeft(QPoint(left,top));
2774    positionCorners.setBottomRight(QPoint(right,bottom));
2775    //save also the inv matrix
2776    matrixWorld_inv = param_matrixWorld.inverted();
2777
2778    //viewport()->update();
2779}
2780
2781void DefaultViewPort::moveView(QPointF delta)
2782{
2783    param_matrixWorld.translate(delta.x(),delta.y());
2784    controlImagePosition();
2785    viewport()->update();
2786}
2787
2788//factor is -0.5 (zoom out) or 0.5 (zoom in)
2789void DefaultViewPort::scaleView(qreal factor,QPointF center)
2790{
2791    factor/=5;//-0.1 <-> 0.1
2792    factor+=1;//0.9 <-> 1.1
2793
2794    //limit zoom out ---
2795    if (param_matrixWorld.m11()==1 && factor < 1)
2796        return;
2797
2798    if (param_matrixWorld.m11()*factor<1)
2799        factor = 1/param_matrixWorld.m11();
2800
2801
2802    //limit zoom int ---
2803    if (param_matrixWorld.m11()>100 && factor > 1)
2804        return;
2805
2806    //inverse the transform
2807    int a, b;
2808    matrixWorld_inv.map(center.x(),center.y(),&a,&b);
2809
2810    param_matrixWorld.translate(a-factor*a,b-factor*b);
2811    param_matrixWorld.scale(factor,factor);
2812
2813    controlImagePosition();
2814
2815    //display new zoom
2816    if (centralWidget->myStatusBar)
2817        centralWidget->displayStatusBar(tr("Zoom: %1%").arg(param_matrixWorld.m11()*100),1000);
2818
2819    if (param_matrixWorld.m11()>1)
2820        setCursor(Qt::OpenHandCursor);
2821    else
2822        unsetCursor();
2823}
2824
2825
2826//up, down, dclick, move
2827void DefaultViewPort::icvmouseHandler(QMouseEvent *evnt, type_mouse_event category, int &cv_event, int &flags)
2828{
2829    Qt::KeyboardModifiers modifiers = evnt->modifiers();
2830    Qt::MouseButtons buttons = evnt->buttons();
2831
2832    flags = 0;
2833    if(modifiers & Qt::ShiftModifier)
2834        flags |= CV_EVENT_FLAG_SHIFTKEY;
2835    if(modifiers & Qt::ControlModifier)
2836        flags |= CV_EVENT_FLAG_CTRLKEY;
2837    if(modifiers & Qt::AltModifier)
2838        flags |= CV_EVENT_FLAG_ALTKEY;
2839
2840    if(buttons & Qt::LeftButton)
2841        flags |= CV_EVENT_FLAG_LBUTTON;
2842    if(buttons & Qt::RightButton)
2843        flags |= CV_EVENT_FLAG_RBUTTON;
2844    if(buttons & Qt::MidButton)
2845        flags |= CV_EVENT_FLAG_MBUTTON;
2846
2847    cv_event = CV_EVENT_MOUSEMOVE;
2848    switch(evnt->button())
2849    {
2850    case Qt::LeftButton:
2851        cv_event = tableMouseButtons[category][0];
2852        flags |= CV_EVENT_FLAG_LBUTTON;
2853        break;
2854    case Qt::RightButton:
2855        cv_event = tableMouseButtons[category][1];
2856        flags |= CV_EVENT_FLAG_RBUTTON;
2857        break;
2858    case Qt::MidButton:
2859        cv_event = tableMouseButtons[category][2];
2860        flags |= CV_EVENT_FLAG_MBUTTON;
2861        break;
2862    default:;
2863    }
2864}
2865
2866
2867void DefaultViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
2868{
2869    //to convert mouse coordinate
2870    qreal pfx, pfy;
2871    matrixWorld_inv.map(pt.x(),pt.y(),&pfx,&pfy);
2872
2873    mouseCoordinate.rx()=floor(pfx/ratioX);
2874    mouseCoordinate.ry()=floor(pfy/ratioY);
2875
2876    if (on_mouse)
2877        on_mouse( cv_event, mouseCoordinate.x(),
2878            mouseCoordinate.y(), flags, on_mouse_param );
2879}
2880
2881
2882QSize DefaultViewPort::sizeHint() const
2883{
2884    if(image2Draw_mat)
2885        return QSize(image2Draw_mat->cols, image2Draw_mat->rows);
2886    else
2887        return QGraphicsView::sizeHint();
2888}
2889
2890
2891void DefaultViewPort::draw2D(QPainter *painter)
2892{
2893    image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows,image2Draw_mat->step,QImage::Format_RGB888);
2894    painter->drawImage(QRect(0,0,viewport()->width(),viewport()->height()), image2Draw_qt, QRect(0,0, image2Draw_qt.width(), image2Draw_qt.height()) );
2895}
2896
2897//only if CV_8UC1 or CV_8UC3
2898void DefaultViewPort::drawStatusBar()
2899{
2900    if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3)
2901        return;
2902
2903    if (mouseCoordinate.x()>=0 &&
2904        mouseCoordinate.y()>=0 &&
2905        mouseCoordinate.x()<image2Draw_qt.width() &&
2906        mouseCoordinate.y()<image2Draw_qt.height())
2907//  if (mouseCoordinate.x()>=0 && mouseCoordinate.y()>=0)
2908    {
2909        QRgb rgbValue = image2Draw_qt.pixel(mouseCoordinate);
2910
2911        if (nbChannelOriginImage==CV_8UC3 )
2912        {
2913            centralWidget->myStatusBar_msg->setText(tr("<font color='black'>(x=%1, y=%2) ~ </font>")
2914                .arg(mouseCoordinate.x())
2915                .arg(mouseCoordinate.y())+
2916                tr("<font color='red'>R:%3 </font>").arg(qRed(rgbValue))+//.arg(value.val[0])+
2917                tr("<font color='green'>G:%4 </font>").arg(qGreen(rgbValue))+//.arg(value.val[1])+
2918                tr("<font color='blue'>B:%5</font>").arg(qBlue(rgbValue))//.arg(value.val[2])
2919                );
2920        }
2921
2922        if (nbChannelOriginImage==CV_8UC1)
2923        {
2924            //all the channel have the same value (because of cvconvertimage), so only the r channel is dsplayed
2925            centralWidget->myStatusBar_msg->setText(tr("<font color='black'>(x=%1, y=%2) ~ </font>")
2926                .arg(mouseCoordinate.x())
2927                .arg(mouseCoordinate.y())+
2928                tr("<font color='grey'>L:%3 </font>").arg(qRed(rgbValue))
2929                );
2930        }
2931    }
2932}
2933
2934//accept only CV_8UC1 and CV_8UC8 image for now
2935void DefaultViewPort::drawImgRegion(QPainter *painter)
2936{
2937    if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3)
2938        return;
2939
2940    double pixel_width = param_matrixWorld.m11()*ratioX;
2941    double pixel_height = param_matrixWorld.m11()*ratioY;
2942
2943    qreal offsetX = param_matrixWorld.dx()/pixel_width;
2944    offsetX = offsetX - floor(offsetX);
2945    qreal offsetY = param_matrixWorld.dy()/pixel_height;
2946    offsetY = offsetY - floor(offsetY);
2947
2948    QSize view = size();
2949    QVarLengthArray<QLineF, 30> linesX;
2950    for (qreal _x = offsetX*pixel_width; _x < view.width(); _x += pixel_width )
2951        linesX.append(QLineF(_x, 0, _x, view.height()));
2952
2953    QVarLengthArray<QLineF, 30> linesY;
2954    for (qreal _y = offsetY*pixel_height; _y < view.height(); _y += pixel_height )
2955        linesY.append(QLineF(0, _y, view.width(), _y));
2956
2957
2958    QFont f = painter->font();
2959    int original_font_size = f.pointSize();
2960    //change font size
2961    //f.setPointSize(4+(param_matrixWorld.m11()-threshold_zoom_img_region)/5);
2962    f.setPixelSize(10+(pixel_height-threshold_zoom_img_region)/5);
2963    painter->setFont(f);
2964
2965
2966    for (int j=-1;j<height()/pixel_height;j++)//-1 because display the pixels top rows left columns
2967        for (int i=-1;i<width()/pixel_width;i++)//-1
2968        {
2969            // Calculate top left of the pixel's position in the viewport (screen space)
2970            QPointF pos_in_view((i+offsetX)*pixel_width, (j+offsetY)*pixel_height);
2971
2972            // Calculate top left of the pixel's position in the image (image space)
2973            QPointF pos_in_image = matrixWorld_inv.map(pos_in_view);// Top left of pixel in view
2974            pos_in_image.rx() = pos_in_image.x()/ratioX;
2975            pos_in_image.ry() = pos_in_image.y()/ratioY;
2976            QPoint point_in_image(pos_in_image.x() + 0.5f,pos_in_image.y() + 0.5f);// Add 0.5 for rounding
2977
2978            QRgb rgbValue;
2979            if (image2Draw_qt.valid(point_in_image))
2980                rgbValue = image2Draw_qt.pixel(point_in_image);
2981            else
2982                rgbValue = qRgb(0,0,0);
2983
2984            if (nbChannelOriginImage==CV_8UC3)
2985            {
2986                //for debug
2987                /*
2988                val = tr("%1 %2").arg(point2.x()).arg(point2.y());
2989                painter->setPen(QPen(Qt::black, 1));
2990                painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/2),
2991                    Qt::AlignCenter, val);
2992                */
2993                QString val;
2994
2995                val = tr("%1").arg(qRed(rgbValue));
2996                painter->setPen(QPen(Qt::red, 1));
2997                painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height/3),
2998                    Qt::AlignCenter, val);
2999
3000                val = tr("%1").arg(qGreen(rgbValue));
3001                painter->setPen(QPen(Qt::green, 1));
3002                painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+pixel_height/3,pixel_width,pixel_height/3),
3003                    Qt::AlignCenter, val);
3004
3005                val = tr("%1").arg(qBlue(rgbValue));
3006                painter->setPen(QPen(Qt::blue, 1));
3007                painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+2*pixel_height/3,pixel_width,pixel_height/3),
3008                    Qt::AlignCenter, val);
3009
3010            }
3011
3012            if (nbChannelOriginImage==CV_8UC1)
3013            {
3014                QString val = tr("%1").arg(qRed(rgbValue));
3015                painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height),
3016                    Qt::AlignCenter, val);
3017            }
3018        }
3019
3020        painter->setPen(QPen(Qt::black, 1));
3021        painter->drawLines(linesX.data(), linesX.size());
3022        painter->drawLines(linesY.data(), linesY.size());
3023
3024        //restore font size
3025        f.setPointSize(original_font_size);
3026        painter->setFont(f);
3027
3028}
3029
3030void DefaultViewPort::drawViewOverview(QPainter *painter)
3031{
3032    QSize viewSize = size();
3033    viewSize.scale ( 100, 100,Qt::KeepAspectRatio );
3034
3035    const int margin = 5;
3036
3037    //draw the image's location
3038    painter->setBrush(QColor(0, 0, 0, 127));
3039    painter->setPen(Qt::darkGreen);
3040    painter->drawRect(QRect(width()-viewSize.width()-margin, 0,viewSize.width(),viewSize.height()));
3041
3042    //daw the view's location inside the image
3043    qreal ratioSize = 1/param_matrixWorld.m11();
3044    qreal ratioWindow = (qreal)(viewSize.height())/(qreal)(size().height());
3045    painter->setPen(Qt::darkBlue);
3046    painter->drawRect(QRectF(width()-viewSize.width()-positionCorners.left()*ratioSize*ratioWindow-margin,
3047        -positionCorners.top()*ratioSize*ratioWindow,
3048        (viewSize.width()-1)*ratioSize,
3049        (viewSize.height()-1)*ratioSize)
3050        );
3051}
3052
3053void DefaultViewPort::drawInstructions(QPainter *painter)
3054{
3055    QFontMetrics metrics = QFontMetrics(font());
3056    int border = qMax(4, metrics.leading());
3057
3058    QRect qrect = metrics.boundingRect(0, 0, width() - 2*border, int(height()*0.125),
3059        Qt::AlignCenter | Qt::TextWordWrap, infoText);
3060    painter->setRenderHint(QPainter::TextAntialiasing);
3061    painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border),
3062        QColor(0, 0, 0, 127));
3063    painter->setPen(Qt::white);
3064    painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border),
3065        QColor(0, 0, 0, 127));
3066
3067    painter->drawText((width() - qrect.width())/2, border,
3068        qrect.width(), qrect.height(),
3069        Qt::AlignCenter | Qt::TextWordWrap, infoText);
3070}
3071
3072
3073void DefaultViewPort::setSize(QSize /*size_*/)
3074{
3075}
3076
3077
3078//////////////////////////////////////////////////////
3079// OpenGlViewPort
3080
3081#ifdef HAVE_QT_OPENGL
3082
3083OpenGlViewPort::OpenGlViewPort(QWidget* _parent) : QGLWidget(_parent), size(-1, -1)
3084{
3085    mouseCallback = 0;
3086    mouseData = 0;
3087
3088    glDrawCallback = 0;
3089    glDrawData = 0;
3090}
3091
3092OpenGlViewPort::~OpenGlViewPort()
3093{
3094}
3095
3096QWidget* OpenGlViewPort::getWidget()
3097{
3098    return this;
3099}
3100
3101void OpenGlViewPort::setMouseCallBack(CvMouseCallback callback, void* param)
3102{
3103    mouseCallback = callback;
3104    mouseData = param;
3105}
3106
3107void OpenGlViewPort::writeSettings(QSettings& /*settings*/)
3108{
3109}
3110
3111void OpenGlViewPort::readSettings(QSettings& /*settings*/)
3112{
3113}
3114
3115double OpenGlViewPort::getRatio()
3116{
3117    return (double)width() / height();
3118}
3119
3120void OpenGlViewPort::setRatio(int /*flags*/)
3121{
3122}
3123
3124void OpenGlViewPort::updateImage(const CvArr* /*arr*/)
3125{
3126}
3127
3128void OpenGlViewPort::startDisplayInfo(QString /*text*/, int /*delayms*/)
3129{
3130}
3131
3132void OpenGlViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata)
3133{
3134    glDrawCallback = callback;
3135    glDrawData = userdata;
3136}
3137
3138void OpenGlViewPort::makeCurrentOpenGlContext()
3139{
3140    makeCurrent();
3141}
3142
3143void OpenGlViewPort::updateGl()
3144{
3145    QGLWidget::updateGL();
3146}
3147
3148void OpenGlViewPort::initializeGL()
3149{
3150    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
3151}
3152
3153void OpenGlViewPort::resizeGL(int w, int h)
3154{
3155    glViewport(0, 0, w, h);
3156}
3157
3158void OpenGlViewPort::paintGL()
3159{
3160    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3161
3162    if (glDrawCallback)
3163        glDrawCallback(glDrawData);
3164}
3165
3166void OpenGlViewPort::mousePressEvent(QMouseEvent* evnt)
3167{
3168    int cv_event = -1, flags = 0;
3169    QPoint pt = evnt->pos();
3170
3171    icvmouseHandler(evnt, mouse_down, cv_event, flags);
3172    icvmouseProcessing(QPointF(pt), cv_event, flags);
3173
3174    QGLWidget::mousePressEvent(evnt);
3175}
3176
3177
3178void OpenGlViewPort::mouseReleaseEvent(QMouseEvent* evnt)
3179{
3180    int cv_event = -1, flags = 0;
3181    QPoint pt = evnt->pos();
3182
3183    icvmouseHandler(evnt, mouse_up, cv_event, flags);
3184    icvmouseProcessing(QPointF(pt), cv_event, flags);
3185
3186    QGLWidget::mouseReleaseEvent(evnt);
3187}
3188
3189
3190void OpenGlViewPort::mouseDoubleClickEvent(QMouseEvent* evnt)
3191{
3192    int cv_event = -1, flags = 0;
3193    QPoint pt = evnt->pos();
3194
3195    icvmouseHandler(evnt, mouse_dbclick, cv_event, flags);
3196    icvmouseProcessing(QPointF(pt), cv_event, flags);
3197
3198    QGLWidget::mouseDoubleClickEvent(evnt);
3199}
3200
3201
3202void OpenGlViewPort::mouseMoveEvent(QMouseEvent* evnt)
3203{
3204    int cv_event = CV_EVENT_MOUSEMOVE, flags = 0;
3205    QPoint pt = evnt->pos();
3206
3207    //icvmouseHandler: pass parameters for cv_event, flags
3208    icvmouseHandler(evnt, mouse_move, cv_event, flags);
3209    icvmouseProcessing(QPointF(pt), cv_event, flags);
3210
3211    QGLWidget::mouseMoveEvent(evnt);
3212}
3213
3214void OpenGlViewPort::icvmouseHandler(QMouseEvent* evnt, type_mouse_event category, int& cv_event, int& flags)
3215{
3216    Qt::KeyboardModifiers modifiers = evnt->modifiers();
3217    Qt::MouseButtons buttons = evnt->buttons();
3218
3219    flags = 0;
3220    if (modifiers & Qt::ShiftModifier)
3221        flags |= CV_EVENT_FLAG_SHIFTKEY;
3222    if (modifiers & Qt::ControlModifier)
3223        flags |= CV_EVENT_FLAG_CTRLKEY;
3224    if (modifiers & Qt::AltModifier)
3225        flags |= CV_EVENT_FLAG_ALTKEY;
3226
3227    if (buttons & Qt::LeftButton)
3228        flags |= CV_EVENT_FLAG_LBUTTON;
3229    if (buttons & Qt::RightButton)
3230        flags |= CV_EVENT_FLAG_RBUTTON;
3231    if (buttons & Qt::MidButton)
3232        flags |= CV_EVENT_FLAG_MBUTTON;
3233
3234    cv_event = CV_EVENT_MOUSEMOVE;
3235    switch (evnt->button())
3236    {
3237    case Qt::LeftButton:
3238        cv_event = tableMouseButtons[category][0];
3239        flags |= CV_EVENT_FLAG_LBUTTON;
3240        break;
3241
3242    case Qt::RightButton:
3243        cv_event = tableMouseButtons[category][1];
3244        flags |= CV_EVENT_FLAG_RBUTTON;
3245        break;
3246
3247    case Qt::MidButton:
3248        cv_event = tableMouseButtons[category][2];
3249        flags |= CV_EVENT_FLAG_MBUTTON;
3250        break;
3251
3252    default:
3253        ;
3254    }
3255}
3256
3257
3258void OpenGlViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
3259{
3260    if (mouseCallback)
3261        mouseCallback(cv_event, pt.x(), pt.y(), flags, mouseData);
3262}
3263
3264
3265QSize OpenGlViewPort::sizeHint() const
3266{
3267    if (size.width() > 0 && size.height() > 0)
3268        return size;
3269
3270    return QGLWidget::sizeHint();
3271}
3272
3273void OpenGlViewPort::setSize(QSize size_)
3274{
3275    size = size_;
3276    updateGeometry();
3277}
3278
3279#endif
3280
3281#endif // HAVE_QT
3282