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