Merge remote-tracking branch 'origin/2.4' into merge-2.4
[platform/upstream/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 = cv::cvarrToMat(mat);
953         cv::imshow(name.toUtf8().data(), 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 received 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     if (!vect_QActions.empty())
1740         vect_QActions[9]->setDisabled(false);
1741 }
1742
1743
1744 CvButtonbar* CvWindow::createButtonBar(QString name_bar)
1745 {
1746     QPointer<CvButtonbar> t = new CvButtonbar(global_control_panel, name_bar);
1747     t->setAlignment(Qt::AlignHCenter);
1748
1749     QPointer<QBoxLayout> myLayout = global_control_panel->myLayout;
1750
1751     myLayout->insertLayout(myLayout->count(), t);
1752
1753     return t;
1754 }
1755
1756
1757 void CvWindow::addSlider(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback on_change)
1758 {
1759     QPointer<CvTrackbar> t = new CvTrackbar(w, name, value, count, on_change);
1760     t->setAlignment(Qt::AlignHCenter);
1761
1762     QPointer<QBoxLayout> myLayout;
1763
1764     if (w)
1765     {
1766         myLayout = w->myBarLayout;
1767     }
1768     else
1769     {
1770         myLayout = global_control_panel->myLayout;
1771
1772         //if first one, enable control panel
1773         if (myLayout->count() == 0)
1774             guiMainThread->enablePropertiesButtonEachWindow();
1775     }
1776
1777     myLayout->insertLayout(myLayout->count(), t);
1778 }
1779
1780
1781 void CvWindow::addSlider2(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback2 on_change, void* userdata)
1782 {
1783     QPointer<CvTrackbar> t = new CvTrackbar(w, name, value, count, on_change, userdata);
1784     t->setAlignment(Qt::AlignHCenter);
1785
1786     QPointer<QBoxLayout> myLayout;
1787
1788     if (w)
1789     {
1790         myLayout = w->myBarLayout;
1791     }
1792     else
1793     {
1794         myLayout = global_control_panel->myLayout;
1795
1796         //if first one, enable control panel
1797         if (myLayout->count() == 0)
1798             guiMainThread->enablePropertiesButtonEachWindow();
1799     }
1800
1801     myLayout->insertLayout(myLayout->count(), t);
1802 }
1803
1804
1805 void CvWindow::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata)
1806 {
1807     myView->setOpenGlDrawCallback(callback, userdata);
1808 }
1809
1810
1811 void CvWindow::makeCurrentOpenGlContext()
1812 {
1813     myView->makeCurrentOpenGlContext();
1814 }
1815
1816
1817 void CvWindow::updateGl()
1818 {
1819     myView->updateGl();
1820 }
1821
1822
1823 bool CvWindow::isOpenGl()
1824 {
1825     return mode_display == CV_MODE_OPENGL;
1826 }
1827
1828
1829 void CvWindow::setViewportSize(QSize _size)
1830 {
1831     myView->getWidget()->resize(_size);
1832     myView->setSize(_size);
1833 }
1834
1835
1836 void CvWindow::createBarLayout()
1837 {
1838     myBarLayout = new QBoxLayout(QBoxLayout::TopToBottom);
1839     myBarLayout->setObjectName(QString::fromUtf8("barLayout"));
1840     myBarLayout->setContentsMargins(0, 0, 0, 0);
1841     myBarLayout->setSpacing(0);
1842     myBarLayout->setMargin(0);
1843 }
1844
1845
1846 void CvWindow::createGlobalLayout()
1847 {
1848     myGlobalLayout = new QBoxLayout(QBoxLayout::TopToBottom);
1849     myGlobalLayout->setObjectName(QString::fromUtf8("boxLayout"));
1850     myGlobalLayout->setContentsMargins(0, 0, 0, 0);
1851     myGlobalLayout->setSpacing(0);
1852     myGlobalLayout->setMargin(0);
1853     setMinimumSize(1, 1);
1854
1855     if (param_flags == CV_WINDOW_AUTOSIZE)
1856         myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize);
1857     else if (param_flags == CV_WINDOW_NORMAL)
1858         myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
1859 }
1860
1861
1862 void CvWindow::createView()
1863 {
1864 #ifdef HAVE_QT_OPENGL
1865     if (isOpenGl())
1866         myView = new OpenGlViewPort(this);
1867     else
1868 #endif
1869         myView = new DefaultViewPort(this, param_ratio_mode);
1870 }
1871
1872
1873 void CvWindow::createActions()
1874 {
1875     vect_QActions.resize(10);
1876
1877     QWidget* view = myView->getWidget();
1878
1879     //if the shortcuts are changed in window_QT.h, we need to update the tooltip manually
1880     vect_QActions[0] = new QAction(QIcon(":/left-icon"), "Panning left (CTRL+arrowLEFT)", this);
1881     vect_QActions[0]->setIconVisibleInMenu(true);
1882     QObject::connect(vect_QActions[0], SIGNAL(triggered()), view, SLOT(siftWindowOnLeft()));
1883
1884     vect_QActions[1] = new QAction(QIcon(":/right-icon"), "Panning right (CTRL+arrowRIGHT)", this);
1885     vect_QActions[1]->setIconVisibleInMenu(true);
1886     QObject::connect(vect_QActions[1], SIGNAL(triggered()), view, SLOT(siftWindowOnRight()));
1887
1888     vect_QActions[2] = new QAction(QIcon(":/up-icon"), "Panning up (CTRL+arrowUP)", this);
1889     vect_QActions[2]->setIconVisibleInMenu(true);
1890     QObject::connect(vect_QActions[2], SIGNAL(triggered()), view, SLOT(siftWindowOnUp()));
1891
1892     vect_QActions[3] = new QAction(QIcon(":/down-icon"), "Panning down (CTRL+arrowDOWN)", this);
1893     vect_QActions[3]->setIconVisibleInMenu(true);
1894     QObject::connect(vect_QActions[3], SIGNAL(triggered()), view, SLOT(siftWindowOnDown()) );
1895
1896     vect_QActions[4] = new QAction(QIcon(":/zoom_x1-icon"), "Zoom x1 (CTRL+P)", this);
1897     vect_QActions[4]->setIconVisibleInMenu(true);
1898     QObject::connect(vect_QActions[4], SIGNAL(triggered()), view, SLOT(resetZoom()));
1899
1900     vect_QActions[5] = new QAction(QIcon(":/imgRegion-icon"), tr("Zoom x%1 (see label) (CTRL+X)").arg(threshold_zoom_img_region), this);
1901     vect_QActions[5]->setIconVisibleInMenu(true);
1902     QObject::connect(vect_QActions[5], SIGNAL(triggered()), view, SLOT(imgRegion()));
1903
1904     vect_QActions[6] = new QAction(QIcon(":/zoom_in-icon"), "Zoom in (CTRL++)", this);
1905     vect_QActions[6]->setIconVisibleInMenu(true);
1906     QObject::connect(vect_QActions[6], SIGNAL(triggered()), view, SLOT(ZoomIn()));
1907
1908     vect_QActions[7] = new QAction(QIcon(":/zoom_out-icon"), "Zoom out (CTRL+-)", this);
1909     vect_QActions[7]->setIconVisibleInMenu(true);
1910     QObject::connect(vect_QActions[7], SIGNAL(triggered()), view, SLOT(ZoomOut()));
1911
1912     vect_QActions[8] = new QAction(QIcon(":/save-icon"), "Save current image (CTRL+S)", this);
1913     vect_QActions[8]->setIconVisibleInMenu(true);
1914     QObject::connect(vect_QActions[8], SIGNAL(triggered()), view, SLOT(saveView()));
1915
1916     vect_QActions[9] = new QAction(QIcon(":/properties-icon"), "Display properties window (CTRL+P)", this);
1917     vect_QActions[9]->setIconVisibleInMenu(true);
1918     QObject::connect(vect_QActions[9], SIGNAL(triggered()), this, SLOT(displayPropertiesWin()));
1919
1920     if (global_control_panel->myLayout->count() == 0)
1921         vect_QActions[9]->setDisabled(true);
1922 }
1923
1924
1925 void CvWindow::createShortcuts()
1926 {
1927     vect_QShortcuts.resize(10);
1928
1929     QWidget* view = myView->getWidget();
1930
1931     vect_QShortcuts[0] = new QShortcut(shortcut_panning_left, this);
1932     QObject::connect(vect_QShortcuts[0], SIGNAL(activated()), view, SLOT(siftWindowOnLeft()));
1933
1934     vect_QShortcuts[1] = new QShortcut(shortcut_panning_right, this);
1935     QObject::connect(vect_QShortcuts[1], SIGNAL(activated()), view, SLOT(siftWindowOnRight()));
1936
1937     vect_QShortcuts[2] = new QShortcut(shortcut_panning_up, this);
1938     QObject::connect(vect_QShortcuts[2], SIGNAL(activated()), view, SLOT(siftWindowOnUp()));
1939
1940     vect_QShortcuts[3] = new QShortcut(shortcut_panning_down, this);
1941     QObject::connect(vect_QShortcuts[3], SIGNAL(activated()), view, SLOT(siftWindowOnDown()));
1942
1943     vect_QShortcuts[4] = new QShortcut(shortcut_zoom_normal, this);
1944     QObject::connect(vect_QShortcuts[4], SIGNAL(activated()), view, SLOT(resetZoom()));
1945
1946     vect_QShortcuts[5] = new QShortcut(shortcut_zoom_imgRegion, this);
1947     QObject::connect(vect_QShortcuts[5], SIGNAL(activated()), view, SLOT(imgRegion()));
1948
1949     vect_QShortcuts[6] = new QShortcut(shortcut_zoom_in, this);
1950     QObject::connect(vect_QShortcuts[6], SIGNAL(activated()), view, SLOT(ZoomIn()));
1951
1952     vect_QShortcuts[7] = new QShortcut(shortcut_zoom_out, this);
1953     QObject::connect(vect_QShortcuts[7], SIGNAL(activated()), view, SLOT(ZoomOut()));
1954
1955     vect_QShortcuts[8] = new QShortcut(shortcut_save_img, this);
1956     QObject::connect(vect_QShortcuts[8], SIGNAL(activated()), view, SLOT(saveView()));
1957
1958     vect_QShortcuts[9] = new QShortcut(shortcut_properties_win, this);
1959     QObject::connect(vect_QShortcuts[9], SIGNAL(activated()), this, SLOT(displayPropertiesWin()));
1960 }
1961
1962
1963 void CvWindow::createToolBar()
1964 {
1965     myToolBar = new QToolBar(this);
1966     myToolBar->setFloatable(false); //is not a window
1967     myToolBar->setFixedHeight(28);
1968     myToolBar->setMinimumWidth(1);
1969
1970     foreach (QAction *a, vect_QActions)
1971         myToolBar->addAction(a);
1972 }
1973
1974
1975 void CvWindow::createStatusBar()
1976 {
1977     myStatusBar = new QStatusBar(this);
1978     myStatusBar->setSizeGripEnabled(false);
1979     myStatusBar->setFixedHeight(20);
1980     myStatusBar->setMinimumWidth(1);
1981     myStatusBar_msg = new QLabel;
1982
1983     //I comment this because if we change the style, myview (the picture)
1984     //will not be the correct size anymore (will lost 2 pixel because of the borders)
1985
1986     //myStatusBar_msg->setFrameStyle(QFrame::Raised);
1987
1988     myStatusBar_msg->setAlignment(Qt::AlignHCenter);
1989     myStatusBar->addWidget(myStatusBar_msg);
1990 }
1991
1992
1993 void CvWindow::hideTools()
1994 {
1995     if (myToolBar)
1996         myToolBar->hide();
1997
1998     if (myStatusBar)
1999         myStatusBar->hide();
2000
2001     if (global_control_panel)
2002         global_control_panel->hide();
2003 }
2004
2005
2006 void CvWindow::showTools()
2007 {
2008     if (myToolBar)
2009         myToolBar->show();
2010
2011     if (myStatusBar)
2012         myStatusBar->show();
2013 }
2014
2015
2016 CvWinProperties* CvWindow::createParameterWindow()
2017 {
2018     QString name_paraWindow = QFileInfo(QApplication::applicationFilePath()).fileName() + " settings";
2019
2020     CvWinProperties* result = new CvWinProperties(name_paraWindow, guiMainThread);
2021
2022     return result;
2023 }
2024
2025
2026 void CvWindow::displayPropertiesWin()
2027 {
2028     if (global_control_panel->isHidden())
2029         global_control_panel->show();
2030     else
2031         global_control_panel->hide();
2032 }
2033
2034
2035 //Need more test here !
2036 void CvWindow::keyPressEvent(QKeyEvent *evnt)
2037 {
2038     //see http://doc.trolltech.com/4.6/qt.html#Key-enum
2039     int key = evnt->key();
2040
2041         Qt::Key qtkey = static_cast<Qt::Key>(key);
2042         char asciiCode = QTest::keyToAscii(qtkey);
2043         if (asciiCode != 0)
2044             key = static_cast<int>(asciiCode);
2045         else
2046             key = evnt->nativeVirtualKey(); //same codes as returned by GTK-based backend
2047
2048     //control plus (Z, +, -, up, down, left, right) are used for zoom/panning functions
2049         if (evnt->modifiers() != Qt::ControlModifier)
2050         {
2051         mutexKey.lock();
2052         last_key = key;
2053         mutexKey.unlock();
2054         key_pressed.wakeAll();
2055         //evnt->accept();
2056     }
2057
2058     QWidget::keyPressEvent(evnt);
2059 }
2060
2061
2062 void CvWindow::icvLoadControlPanel()
2063 {
2064     QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName() + " control panel");
2065
2066     int bsize = settings.beginReadArray("bars");
2067
2068     if (bsize == global_control_panel->myLayout->layout()->count())
2069     {
2070         for (int i = 0; i < bsize; ++i)
2071         {
2072             CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i);
2073             settings.setArrayIndex(i);
2074             if (t->type == type_CvTrackbar)
2075             {
2076                 if (t->name_bar == settings.value("namebar").toString())
2077                 {
2078                     ((CvTrackbar*)t)->slider->setValue(settings.value("valuebar").toInt());
2079                 }
2080             }
2081             if (t->type == type_CvButtonbar)
2082             {
2083                 int subsize = settings.beginReadArray(QString("buttonbar")+i);
2084
2085                 if ( subsize == ((CvButtonbar*)t)->layout()->count() )
2086                     icvLoadButtonbar((CvButtonbar*)t,&settings);
2087
2088                 settings.endArray();
2089             }
2090         }
2091     }
2092
2093     settings.endArray();
2094 }
2095
2096
2097 void CvWindow::icvSaveControlPanel()
2098 {
2099     QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()+" control panel");
2100
2101     settings.beginWriteArray("bars");
2102
2103     for (int i = 0; i < global_control_panel->myLayout->layout()->count(); ++i)
2104     {
2105         CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i);
2106         settings.setArrayIndex(i);
2107         if (t->type == type_CvTrackbar)
2108         {
2109             settings.setValue("namebar", QString(t->name_bar));
2110             settings.setValue("valuebar",((CvTrackbar*)t)->slider->value());
2111         }
2112         if (t->type == type_CvButtonbar)
2113         {
2114             settings.beginWriteArray(QString("buttonbar")+i);
2115             icvSaveButtonbar((CvButtonbar*)t,&settings);
2116             settings.endArray();
2117         }
2118     }
2119
2120     settings.endArray();
2121 }
2122
2123
2124 void CvWindow::icvSaveButtonbar(CvButtonbar* b, QSettings* settings)
2125 {
2126     for (int i = 0, count = b->layout()->count(); i < count; ++i)
2127     {
2128         settings->setArrayIndex(i);
2129
2130         QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget();
2131         QString myclass(QLatin1String(temp->metaObject()->className()));
2132
2133         if (myclass == "CvPushButton")
2134         {
2135             CvPushButton* button = (CvPushButton*) temp;
2136             settings->setValue("namebutton", button->text());
2137             settings->setValue("valuebutton", int(button->isChecked()));
2138         }
2139         else if (myclass == "CvCheckBox")
2140         {
2141             CvCheckBox* button = (CvCheckBox*) temp;
2142             settings->setValue("namebutton", button->text());
2143             settings->setValue("valuebutton", int(button->isChecked()));
2144         }
2145         else if (myclass == "CvRadioButton")
2146         {
2147             CvRadioButton* button = (CvRadioButton*) temp;
2148             settings->setValue("namebutton", button->text());
2149             settings->setValue("valuebutton", int(button->isChecked()));
2150         }
2151     }
2152 }
2153
2154
2155 void CvWindow::icvLoadButtonbar(CvButtonbar* b, QSettings* settings)
2156 {
2157     for (int i = 0, count = b->layout()->count(); i < count; ++i)
2158     {
2159         settings->setArrayIndex(i);
2160
2161         QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget();
2162         QString myclass(QLatin1String(temp->metaObject()->className()));
2163
2164         if (myclass == "CvPushButton")
2165         {
2166             CvPushButton* button = (CvPushButton*) temp;
2167
2168             if (button->text() == settings->value("namebutton").toString())
2169                 button->setChecked(settings->value("valuebutton").toInt());
2170         }
2171         else if (myclass == "CvCheckBox")
2172         {
2173             CvCheckBox* button = (CvCheckBox*) temp;
2174
2175             if (button->text() == settings->value("namebutton").toString())
2176                 button->setChecked(settings->value("valuebutton").toInt());
2177         }
2178         else if (myclass == "CvRadioButton")
2179         {
2180             CvRadioButton* button = (CvRadioButton*) temp;
2181
2182             if (button->text() == settings->value("namebutton").toString())
2183                 button->setChecked(settings->value("valuebutton").toInt());
2184         }
2185
2186     }
2187 }
2188
2189
2190 void CvWindow::icvLoadTrackbars(QSettings* settings)
2191 {
2192     int bsize = settings->beginReadArray("trackbars");
2193
2194     //trackbar are saved in the same order, so no need to use icvFindTrackbarByName
2195
2196     if (myBarLayout->layout()->count() == bsize) //if not the same number, the window saved and loaded is not the same (nb trackbar not equal)
2197     {
2198         for (int i = 0; i < bsize; ++i)
2199         {
2200             settings->setArrayIndex(i);
2201
2202             CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i);
2203
2204             if (t->name_bar == settings->value("name").toString())
2205                 t->slider->setValue(settings->value("value").toInt());
2206
2207         }
2208     }
2209
2210     settings->endArray();
2211 }
2212
2213
2214 void CvWindow::icvSaveTrackbars(QSettings* settings)
2215 {
2216     settings->beginWriteArray("trackbars");
2217
2218     for (int i = 0; i < myBarLayout->layout()->count(); ++i)
2219     {
2220         settings->setArrayIndex(i);
2221
2222         CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i);
2223
2224         settings->setValue("name", t->name_bar);
2225         settings->setValue("value", t->slider->value());
2226     }
2227
2228     settings->endArray();
2229 }
2230
2231
2232 //////////////////////////////////////////////////////
2233 // DefaultViewPort
2234
2235
2236 DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg), image2Draw_mat(0)
2237 {
2238     centralWidget = arg;
2239     param_keepRatio = arg2;
2240
2241     setContentsMargins(0, 0, 0, 0);
2242     setMinimumSize(1, 1);
2243     setAlignment(Qt::AlignHCenter);
2244
2245     setObjectName(QString::fromUtf8("graphicsView"));
2246
2247     timerDisplay = new QTimer(this);
2248     timerDisplay->setSingleShot(true);
2249     connect(timerDisplay, SIGNAL(timeout()), this, SLOT(stopDisplayInfo()));
2250
2251     drawInfo = false;
2252     positionGrabbing = QPointF(0, 0);
2253     positionCorners = QRect(0, 0, size().width(), size().height());
2254
2255     on_mouse = 0;
2256     on_mouse_param = 0;
2257     mouseCoordinate = QPoint(-1, -1);
2258
2259     //no border
2260     setStyleSheet( "QGraphicsView { border-style: none; }" );
2261
2262     image2Draw_mat = cvCreateMat(viewport()->height(), viewport()->width(), CV_8UC3);
2263     cvZero(image2Draw_mat);
2264
2265     nbChannelOriginImage = 0;
2266
2267     setInteractive(false);
2268     setMouseTracking(true); //receive mouse event everytime
2269 }
2270
2271
2272 DefaultViewPort::~DefaultViewPort()
2273 {
2274     if (image2Draw_mat)
2275         cvReleaseMat(&image2Draw_mat);
2276 }
2277
2278
2279 QWidget* DefaultViewPort::getWidget()
2280 {
2281     return this;
2282 }
2283
2284
2285 void DefaultViewPort::setMouseCallBack(CvMouseCallback m, void* param)
2286 {
2287     on_mouse = m;
2288
2289     on_mouse_param = param;
2290 }
2291
2292 void DefaultViewPort::writeSettings(QSettings& settings)
2293 {
2294     settings.setValue("matrix_view.m11", param_matrixWorld.m11());
2295     settings.setValue("matrix_view.m12", param_matrixWorld.m12());
2296     settings.setValue("matrix_view.m13", param_matrixWorld.m13());
2297     settings.setValue("matrix_view.m21", param_matrixWorld.m21());
2298     settings.setValue("matrix_view.m22", param_matrixWorld.m22());
2299     settings.setValue("matrix_view.m23", param_matrixWorld.m23());
2300     settings.setValue("matrix_view.m31", param_matrixWorld.m31());
2301     settings.setValue("matrix_view.m32", param_matrixWorld.m32());
2302     settings.setValue("matrix_view.m33", param_matrixWorld.m33());
2303 }
2304
2305
2306 void DefaultViewPort::readSettings(QSettings& settings)
2307 {
2308     qreal m11 = settings.value("matrix_view.m11", param_matrixWorld.m11()).toDouble();
2309     qreal m12 = settings.value("matrix_view.m12", param_matrixWorld.m12()).toDouble();
2310     qreal m13 = settings.value("matrix_view.m13", param_matrixWorld.m13()).toDouble();
2311     qreal m21 = settings.value("matrix_view.m21", param_matrixWorld.m21()).toDouble();
2312     qreal m22 = settings.value("matrix_view.m22", param_matrixWorld.m22()).toDouble();
2313     qreal m23 = settings.value("matrix_view.m23", param_matrixWorld.m23()).toDouble();
2314     qreal m31 = settings.value("matrix_view.m31", param_matrixWorld.m31()).toDouble();
2315     qreal m32 = settings.value("matrix_view.m32", param_matrixWorld.m32()).toDouble();
2316     qreal m33 = settings.value("matrix_view.m33", param_matrixWorld.m33()).toDouble();
2317
2318     param_matrixWorld = QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33);
2319 }
2320
2321
2322 double DefaultViewPort::getRatio()
2323 {
2324     return param_keepRatio;
2325 }
2326
2327
2328 void DefaultViewPort::setRatio(int flags)
2329 {
2330     if (getRatio() == flags) //nothing to do
2331         return;
2332
2333     //if valid flags
2334     if (flags == CV_WINDOW_FREERATIO || flags == CV_WINDOW_KEEPRATIO)
2335     {
2336         centralWidget->param_ratio_mode = flags;
2337         param_keepRatio = flags;
2338         updateGeometry();
2339         viewport()->update();
2340     }
2341 }
2342
2343
2344 void DefaultViewPort::updateImage(const CvArr* arr)
2345 {
2346     CV_Assert(arr);
2347
2348     CvMat* mat, stub;
2349     int origin = 0;
2350
2351     if (CV_IS_IMAGE_HDR(arr))
2352         origin = ((IplImage*)arr)->origin;
2353
2354     mat = cvGetMat(arr, &stub);
2355
2356     if (!image2Draw_mat || !CV_ARE_SIZES_EQ(image2Draw_mat, mat))
2357     {
2358         if (image2Draw_mat)
2359             cvReleaseMat(&image2Draw_mat);
2360
2361         //the image in ipl (to do a deep copy with cvCvtColor)
2362         image2Draw_mat = cvCreateMat(mat->rows, mat->cols, CV_8UC3);
2363         image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows, image2Draw_mat->step, QImage::Format_RGB888);
2364
2365         //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent
2366         ratioX = width() / float(image2Draw_mat->cols);
2367         ratioY = height() / float(image2Draw_mat->rows);
2368
2369         updateGeometry();
2370     }
2371
2372     nbChannelOriginImage = cvGetElemType(mat);
2373
2374     cvConvertImage(mat, image2Draw_mat, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB);
2375
2376     viewport()->update();
2377 }
2378
2379
2380 void DefaultViewPort::startDisplayInfo(QString text, int delayms)
2381 {
2382     if (timerDisplay->isActive())
2383         stopDisplayInfo();
2384
2385     infoText = text;
2386     if (delayms > 0) timerDisplay->start(delayms);
2387     drawInfo = true;
2388 }
2389
2390
2391 void DefaultViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback /*callback*/, void* /*userdata*/)
2392 {
2393     CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL");
2394 }
2395
2396
2397 void DefaultViewPort::makeCurrentOpenGlContext()
2398 {
2399     CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL");
2400 }
2401
2402
2403 void DefaultViewPort::updateGl()
2404 {
2405     CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL");
2406 }
2407
2408
2409 //Note: move 2 percent of the window
2410 void DefaultViewPort::siftWindowOnLeft()
2411 {
2412     float delta = 2 * width() / (100.0 * param_matrixWorld.m11());
2413     moveView(QPointF(delta, 0));
2414 }
2415
2416
2417 //Note: move 2 percent of the window
2418 void DefaultViewPort::siftWindowOnRight()
2419 {
2420     float delta = -2 * width() / (100.0 * param_matrixWorld.m11());
2421     moveView(QPointF(delta, 0));
2422 }
2423
2424
2425 //Note: move 2 percent of the window
2426 void DefaultViewPort::siftWindowOnUp()
2427 {
2428     float delta = 2 * height() / (100.0 * param_matrixWorld.m11());
2429     moveView(QPointF(0, delta));
2430 }
2431
2432
2433 //Note: move 2 percent of the window
2434 void DefaultViewPort::siftWindowOnDown()
2435 {
2436     float delta = -2 * height() / (100.0 * param_matrixWorld.m11());
2437     moveView(QPointF(0, delta));
2438 }
2439
2440
2441 void DefaultViewPort::imgRegion()
2442 {
2443     scaleView((threshold_zoom_img_region / param_matrixWorld.m11() - 1) * 5, QPointF(size().width() / 2, size().height() / 2));
2444 }
2445
2446
2447 void DefaultViewPort::resetZoom()
2448 {
2449     param_matrixWorld.reset();
2450     controlImagePosition();
2451 }
2452
2453
2454 void DefaultViewPort::ZoomIn()
2455 {
2456     scaleView(0.5, QPointF(size().width() / 2, size().height() / 2));
2457 }
2458
2459
2460 void DefaultViewPort::ZoomOut()
2461 {
2462     scaleView(-0.5, QPointF(size().width() / 2, size().height() / 2));
2463 }
2464
2465
2466 //can save as JPG, JPEG, BMP, PNG
2467 void DefaultViewPort::saveView()
2468 {
2469     QDate date_d = QDate::currentDate();
2470     QString date_s = date_d.toString("dd.MM.yyyy");
2471     QString name_s = centralWidget->windowTitle() + "_screenshot_" + date_s;
2472
2473     QString fileName = QFileDialog::getSaveFileName(this, tr("Save File %1").arg(name_s), name_s + ".png", tr("Images (*.png *.jpg *.bmp *.jpeg)"));
2474
2475     if (!fileName.isEmpty()) //save the picture
2476     {
2477         QString extension = fileName.right(3);
2478
2479         // Create a new pixmap to render the viewport into
2480         QPixmap viewportPixmap(viewport()->size());
2481         viewport()->render(&viewportPixmap);
2482
2483         // Save it..
2484         if (QString::compare(extension, "png", Qt::CaseInsensitive) == 0)
2485         {
2486             viewportPixmap.save(fileName, "PNG");
2487             return;
2488         }
2489
2490         if (QString::compare(extension, "jpg", Qt::CaseInsensitive) == 0)
2491         {
2492             viewportPixmap.save(fileName, "JPG");
2493             return;
2494         }
2495
2496         if (QString::compare(extension, "bmp", Qt::CaseInsensitive) == 0)
2497         {
2498             viewportPixmap.save(fileName, "BMP");
2499             return;
2500         }
2501
2502         if (QString::compare(extension, "jpeg", Qt::CaseInsensitive) == 0)
2503         {
2504             viewportPixmap.save(fileName, "JPEG");
2505             return;
2506         }
2507
2508         CV_Error(CV_StsNullPtr, "file extension not recognized, please choose between JPG, JPEG, BMP or PNG");
2509     }
2510 }
2511
2512
2513 void DefaultViewPort::contextMenuEvent(QContextMenuEvent* evnt)
2514 {
2515     if (centralWidget->vect_QActions.size() > 0)
2516     {
2517         QMenu menu(this);
2518
2519         foreach (QAction *a, centralWidget->vect_QActions)
2520             menu.addAction(a);
2521
2522         menu.exec(evnt->globalPos());
2523     }
2524 }
2525
2526
2527 void DefaultViewPort::resizeEvent(QResizeEvent* evnt)
2528 {
2529     controlImagePosition();
2530
2531     //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent
2532     ratioX = width() / float(image2Draw_mat->cols);
2533     ratioY = height() / float(image2Draw_mat->rows);
2534
2535     if (param_keepRatio == CV_WINDOW_KEEPRATIO)//to keep the same aspect ratio
2536     {
2537         QSize newSize = QSize(image2Draw_mat->cols, image2Draw_mat->rows);
2538         newSize.scale(evnt->size(), Qt::KeepAspectRatio);
2539
2540         //imageWidth/imageHeight = newWidth/newHeight +/- epsilon
2541         //ratioX = ratioY +/- epsilon
2542         //||ratioX - ratioY|| = epsilon
2543         if (fabs(ratioX - ratioY) * 100 > ratioX) //avoid infinity loop / epsilon = 1% of ratioX
2544         {
2545             resize(newSize);
2546
2547             //move to the middle
2548             //newSize get the delta offset to place the picture in the middle of its parent
2549             newSize = (evnt->size() - newSize) / 2;
2550
2551             //if the toolbar is displayed, avoid drawing myview on top of it
2552             if (centralWidget->myToolBar)
2553                 if(!centralWidget->myToolBar->isHidden())
2554                     newSize += QSize(0, centralWidget->myToolBar->height());
2555
2556             move(newSize.width(), newSize.height());
2557         }
2558     }
2559
2560     return QGraphicsView::resizeEvent(evnt);
2561 }
2562
2563
2564 void DefaultViewPort::wheelEvent(QWheelEvent* evnt)
2565 {
2566     scaleView(evnt->delta() / 240.0, evnt->pos());
2567     viewport()->update();
2568 }
2569
2570
2571 void DefaultViewPort::mousePressEvent(QMouseEvent* evnt)
2572 {
2573     int cv_event = -1, flags = 0;
2574     QPoint pt = evnt->pos();
2575
2576     //icvmouseHandler: pass parameters for cv_event, flags
2577     icvmouseHandler(evnt, mouse_down, cv_event, flags);
2578     icvmouseProcessing(QPointF(pt), cv_event, flags);
2579
2580     if (param_matrixWorld.m11()>1)
2581     {
2582         setCursor(Qt::ClosedHandCursor);
2583         positionGrabbing = evnt->pos();
2584     }
2585
2586     QWidget::mousePressEvent(evnt);
2587 }
2588
2589
2590 void DefaultViewPort::mouseReleaseEvent(QMouseEvent* evnt)
2591 {
2592     int cv_event = -1, flags = 0;
2593     QPoint pt = evnt->pos();
2594
2595     //icvmouseHandler: pass parameters for cv_event, flags
2596     icvmouseHandler(evnt, mouse_up, cv_event, flags);
2597     icvmouseProcessing(QPointF(pt), cv_event, flags);
2598
2599     if (param_matrixWorld.m11()>1)
2600         setCursor(Qt::OpenHandCursor);
2601
2602     QWidget::mouseReleaseEvent(evnt);
2603 }
2604
2605
2606 void DefaultViewPort::mouseDoubleClickEvent(QMouseEvent* evnt)
2607 {
2608     int cv_event = -1, flags = 0;
2609     QPoint pt = evnt->pos();
2610
2611     //icvmouseHandler: pass parameters for cv_event, flags
2612     icvmouseHandler(evnt, mouse_dbclick, cv_event, flags);
2613     icvmouseProcessing(QPointF(pt), cv_event, flags);
2614
2615     QWidget::mouseDoubleClickEvent(evnt);
2616 }
2617
2618
2619 void DefaultViewPort::mouseMoveEvent(QMouseEvent* evnt)
2620 {
2621     int cv_event = CV_EVENT_MOUSEMOVE, flags = 0;
2622     QPoint pt = evnt->pos();
2623
2624     //icvmouseHandler: pass parameters for cv_event, flags
2625     icvmouseHandler(evnt, mouse_move, cv_event, flags);
2626     icvmouseProcessing(QPointF(pt), cv_event, flags);
2627
2628     if (param_matrixWorld.m11() > 1 && evnt->buttons() == Qt::LeftButton)
2629     {
2630         QPointF dxy = (pt - positionGrabbing)/param_matrixWorld.m11();
2631         positionGrabbing = evnt->pos();
2632         moveView(dxy);
2633     }
2634
2635     //I update the statusbar here because if the user does a cvWaitkey(0) (like with inpaint.cpp)
2636     //the status bar will only be repaint when a click occurs.
2637     if (centralWidget->myStatusBar)
2638         viewport()->update();
2639
2640     QWidget::mouseMoveEvent(evnt);
2641 }
2642
2643
2644 void DefaultViewPort::paintEvent(QPaintEvent* evnt)
2645 {
2646     QPainter myPainter(viewport());
2647     myPainter.setWorldTransform(param_matrixWorld);
2648
2649     draw2D(&myPainter);
2650
2651     //Now disable matrixWorld for overlay display
2652     myPainter.setWorldMatrixEnabled(false);
2653
2654     //overlay pixel values if zoomed in far enough
2655     if (param_matrixWorld.m11()*ratioX >= threshold_zoom_img_region &&
2656         param_matrixWorld.m11()*ratioY >= threshold_zoom_img_region)
2657     {
2658         drawImgRegion(&myPainter);
2659     }
2660
2661     //in mode zoom/panning
2662     if (param_matrixWorld.m11() > 1)
2663     {
2664         drawViewOverview(&myPainter);
2665     }
2666
2667     //for information overlay
2668     if (drawInfo)
2669         drawInstructions(&myPainter);
2670
2671     //for statusbar
2672     if (centralWidget->myStatusBar)
2673         drawStatusBar();
2674
2675     QGraphicsView::paintEvent(evnt);
2676 }
2677
2678
2679 void DefaultViewPort::stopDisplayInfo()
2680 {
2681     timerDisplay->stop();
2682     drawInfo = false;
2683 }
2684
2685
2686 inline bool DefaultViewPort::isSameSize(IplImage* img1, IplImage* img2)
2687 {
2688     return img1->width == img2->width && img1->height == img2->height;
2689 }
2690
2691
2692 void DefaultViewPort::controlImagePosition()
2693 {
2694     qreal left, top, right, bottom;
2695
2696     //after check top-left, bottom right corner to avoid getting "out" during zoom/panning
2697     param_matrixWorld.map(0,0,&left,&top);
2698
2699     if (left > 0)
2700     {
2701         param_matrixWorld.translate(-left,0);
2702         left = 0;
2703     }
2704     if (top > 0)
2705     {
2706         param_matrixWorld.translate(0,-top);
2707         top = 0;
2708     }
2709     //-------
2710
2711     QSize sizeImage = size();
2712     param_matrixWorld.map(sizeImage.width(),sizeImage.height(),&right,&bottom);
2713     if (right < sizeImage.width())
2714     {
2715         param_matrixWorld.translate(sizeImage.width()-right,0);
2716         right = sizeImage.width();
2717     }
2718     if (bottom < sizeImage.height())
2719     {
2720         param_matrixWorld.translate(0,sizeImage.height()-bottom);
2721         bottom = sizeImage.height();
2722     }
2723
2724     //save corner position
2725     positionCorners.setTopLeft(QPoint(left,top));
2726     positionCorners.setBottomRight(QPoint(right,bottom));
2727     //save also the inv matrix
2728     matrixWorld_inv = param_matrixWorld.inverted();
2729
2730     //viewport()->update();
2731 }
2732
2733 void DefaultViewPort::moveView(QPointF delta)
2734 {
2735     param_matrixWorld.translate(delta.x(),delta.y());
2736     controlImagePosition();
2737     viewport()->update();
2738 }
2739
2740 //factor is -0.5 (zoom out) or 0.5 (zoom in)
2741 void DefaultViewPort::scaleView(qreal factor,QPointF center)
2742 {
2743     factor/=5;//-0.1 <-> 0.1
2744     factor+=1;//0.9 <-> 1.1
2745
2746     //limit zoom out ---
2747     if (param_matrixWorld.m11()==1 && factor < 1)
2748         return;
2749
2750     if (param_matrixWorld.m11()*factor<1)
2751         factor = 1/param_matrixWorld.m11();
2752
2753
2754     //limit zoom int ---
2755     if (param_matrixWorld.m11()>100 && factor > 1)
2756         return;
2757
2758     //inverse the transform
2759     int a, b;
2760     matrixWorld_inv.map(center.x(),center.y(),&a,&b);
2761
2762     param_matrixWorld.translate(a-factor*a,b-factor*b);
2763     param_matrixWorld.scale(factor,factor);
2764
2765     controlImagePosition();
2766
2767     //display new zoom
2768     if (centralWidget->myStatusBar)
2769         centralWidget->displayStatusBar(tr("Zoom: %1%").arg(param_matrixWorld.m11()*100),1000);
2770
2771     if (param_matrixWorld.m11()>1)
2772         setCursor(Qt::OpenHandCursor);
2773     else
2774         unsetCursor();
2775 }
2776
2777
2778 //up, down, dclick, move
2779 void DefaultViewPort::icvmouseHandler(QMouseEvent *evnt, type_mouse_event category, int &cv_event, int &flags)
2780 {
2781     Qt::KeyboardModifiers modifiers = evnt->modifiers();
2782     Qt::MouseButtons buttons = evnt->buttons();
2783
2784     flags = 0;
2785     if(modifiers & Qt::ShiftModifier)
2786         flags |= CV_EVENT_FLAG_SHIFTKEY;
2787     if(modifiers & Qt::ControlModifier)
2788         flags |= CV_EVENT_FLAG_CTRLKEY;
2789     if(modifiers & Qt::AltModifier)
2790         flags |= CV_EVENT_FLAG_ALTKEY;
2791
2792     if(buttons & Qt::LeftButton)
2793         flags |= CV_EVENT_FLAG_LBUTTON;
2794     if(buttons & Qt::RightButton)
2795         flags |= CV_EVENT_FLAG_RBUTTON;
2796     if(buttons & Qt::MidButton)
2797         flags |= CV_EVENT_FLAG_MBUTTON;
2798
2799     cv_event = CV_EVENT_MOUSEMOVE;
2800     switch(evnt->button())
2801     {
2802     case Qt::LeftButton:
2803         cv_event = tableMouseButtons[category][0];
2804         flags |= CV_EVENT_FLAG_LBUTTON;
2805         break;
2806     case Qt::RightButton:
2807         cv_event = tableMouseButtons[category][1];
2808         flags |= CV_EVENT_FLAG_RBUTTON;
2809         break;
2810     case Qt::MidButton:
2811         cv_event = tableMouseButtons[category][2];
2812         flags |= CV_EVENT_FLAG_MBUTTON;
2813         break;
2814     default:;
2815     }
2816 }
2817
2818
2819 void DefaultViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
2820 {
2821     //to convert mouse coordinate
2822     qreal pfx, pfy;
2823     matrixWorld_inv.map(pt.x(),pt.y(),&pfx,&pfy);
2824
2825     mouseCoordinate.rx()=floor(pfx/ratioX);
2826     mouseCoordinate.ry()=floor(pfy/ratioY);
2827
2828     if (on_mouse)
2829         on_mouse( cv_event, mouseCoordinate.x(),
2830             mouseCoordinate.y(), flags, on_mouse_param );
2831 }
2832
2833
2834 QSize DefaultViewPort::sizeHint() const
2835 {
2836     if(image2Draw_mat)
2837         return QSize(image2Draw_mat->cols, image2Draw_mat->rows);
2838     else
2839         return QGraphicsView::sizeHint();
2840 }
2841
2842
2843 void DefaultViewPort::draw2D(QPainter *painter)
2844 {
2845     image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows,image2Draw_mat->step,QImage::Format_RGB888);
2846     painter->drawImage(QRect(0,0,viewport()->width(),viewport()->height()), image2Draw_qt, QRect(0,0, image2Draw_qt.width(), image2Draw_qt.height()) );
2847 }
2848
2849 //only if CV_8UC1 or CV_8UC3
2850 void DefaultViewPort::drawStatusBar()
2851 {
2852     if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3)
2853         return;
2854
2855     if (mouseCoordinate.x()>=0 &&
2856         mouseCoordinate.y()>=0 &&
2857         mouseCoordinate.x()<image2Draw_qt.width() &&
2858         mouseCoordinate.y()<image2Draw_qt.height())
2859 //  if (mouseCoordinate.x()>=0 && mouseCoordinate.y()>=0)
2860     {
2861         QRgb rgbValue = image2Draw_qt.pixel(mouseCoordinate);
2862
2863         if (nbChannelOriginImage==CV_8UC3 )
2864         {
2865             centralWidget->myStatusBar_msg->setText(tr("<font color='black'>(x=%1, y=%2) ~ </font>")
2866                 .arg(mouseCoordinate.x())
2867                 .arg(mouseCoordinate.y())+
2868                 tr("<font color='red'>R:%3 </font>").arg(qRed(rgbValue))+//.arg(value.val[0])+
2869                 tr("<font color='green'>G:%4 </font>").arg(qGreen(rgbValue))+//.arg(value.val[1])+
2870                 tr("<font color='blue'>B:%5</font>").arg(qBlue(rgbValue))//.arg(value.val[2])
2871                 );
2872         }
2873
2874         if (nbChannelOriginImage==CV_8UC1)
2875         {
2876             //all the channel have the same value (because of cvconvertimage), so only the r channel is dsplayed
2877             centralWidget->myStatusBar_msg->setText(tr("<font color='black'>(x=%1, y=%2) ~ </font>")
2878                 .arg(mouseCoordinate.x())
2879                 .arg(mouseCoordinate.y())+
2880                 tr("<font color='grey'>L:%3 </font>").arg(qRed(rgbValue))
2881                 );
2882         }
2883     }
2884 }
2885
2886 //accept only CV_8UC1 and CV_8UC8 image for now
2887 void DefaultViewPort::drawImgRegion(QPainter *painter)
2888 {
2889     if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3)
2890         return;
2891
2892     double pixel_width = param_matrixWorld.m11()*ratioX;
2893     double pixel_height = param_matrixWorld.m11()*ratioY;
2894
2895     qreal offsetX = param_matrixWorld.dx()/pixel_width;
2896     offsetX = offsetX - floor(offsetX);
2897     qreal offsetY = param_matrixWorld.dy()/pixel_height;
2898     offsetY = offsetY - floor(offsetY);
2899
2900     QSize view = size();
2901     QVarLengthArray<QLineF, 30> linesX;
2902     for (qreal _x = offsetX*pixel_width; _x < view.width(); _x += pixel_width )
2903         linesX.append(QLineF(_x, 0, _x, view.height()));
2904
2905     QVarLengthArray<QLineF, 30> linesY;
2906     for (qreal _y = offsetY*pixel_height; _y < view.height(); _y += pixel_height )
2907         linesY.append(QLineF(0, _y, view.width(), _y));
2908
2909
2910     QFont f = painter->font();
2911     int original_font_size = f.pointSize();
2912     //change font size
2913     //f.setPointSize(4+(param_matrixWorld.m11()-threshold_zoom_img_region)/5);
2914     f.setPixelSize(10+(pixel_height-threshold_zoom_img_region)/5);
2915     painter->setFont(f);
2916
2917
2918     for (int j=-1;j<height()/pixel_height;j++)//-1 because display the pixels top rows left columns
2919         for (int i=-1;i<width()/pixel_width;i++)//-1
2920         {
2921             // Calculate top left of the pixel's position in the viewport (screen space)
2922             QPointF pos_in_view((i+offsetX)*pixel_width, (j+offsetY)*pixel_height);
2923
2924             // Calculate top left of the pixel's position in the image (image space)
2925             QPointF pos_in_image = matrixWorld_inv.map(pos_in_view);// Top left of pixel in view
2926             pos_in_image.rx() = pos_in_image.x()/ratioX;
2927             pos_in_image.ry() = pos_in_image.y()/ratioY;
2928             QPoint point_in_image(pos_in_image.x() + 0.5f,pos_in_image.y() + 0.5f);// Add 0.5 for rounding
2929
2930             QRgb rgbValue;
2931             if (image2Draw_qt.valid(point_in_image))
2932                 rgbValue = image2Draw_qt.pixel(point_in_image);
2933             else
2934                 rgbValue = qRgb(0,0,0);
2935
2936             if (nbChannelOriginImage==CV_8UC3)
2937             {
2938                 //for debug
2939                 /*
2940                 val = tr("%1 %2").arg(point2.x()).arg(point2.y());
2941                 painter->setPen(QPen(Qt::black, 1));
2942                 painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/2),
2943                     Qt::AlignCenter, val);
2944                 */
2945                 QString val;
2946
2947                 val = tr("%1").arg(qRed(rgbValue));
2948                 painter->setPen(QPen(Qt::red, 1));
2949                 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height/3),
2950                     Qt::AlignCenter, val);
2951
2952                 val = tr("%1").arg(qGreen(rgbValue));
2953                 painter->setPen(QPen(Qt::green, 1));
2954                 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+pixel_height/3,pixel_width,pixel_height/3),
2955                     Qt::AlignCenter, val);
2956
2957                 val = tr("%1").arg(qBlue(rgbValue));
2958                 painter->setPen(QPen(Qt::blue, 1));
2959                 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+2*pixel_height/3,pixel_width,pixel_height/3),
2960                     Qt::AlignCenter, val);
2961
2962             }
2963
2964             if (nbChannelOriginImage==CV_8UC1)
2965             {
2966                 QString val = tr("%1").arg(qRed(rgbValue));
2967                 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height),
2968                     Qt::AlignCenter, val);
2969             }
2970         }
2971
2972         painter->setPen(QPen(Qt::black, 1));
2973         painter->drawLines(linesX.data(), linesX.size());
2974         painter->drawLines(linesY.data(), linesY.size());
2975
2976         //restore font size
2977         f.setPointSize(original_font_size);
2978         painter->setFont(f);
2979
2980 }
2981
2982 void DefaultViewPort::drawViewOverview(QPainter *painter)
2983 {
2984     QSize viewSize = size();
2985     viewSize.scale ( 100, 100,Qt::KeepAspectRatio );
2986
2987     const int margin = 5;
2988
2989     //draw the image's location
2990     painter->setBrush(QColor(0, 0, 0, 127));
2991     painter->setPen(Qt::darkGreen);
2992     painter->drawRect(QRect(width()-viewSize.width()-margin, 0,viewSize.width(),viewSize.height()));
2993
2994     //daw the view's location inside the image
2995     qreal ratioSize = 1/param_matrixWorld.m11();
2996     qreal ratioWindow = (qreal)(viewSize.height())/(qreal)(size().height());
2997     painter->setPen(Qt::darkBlue);
2998     painter->drawRect(QRectF(width()-viewSize.width()-positionCorners.left()*ratioSize*ratioWindow-margin,
2999         -positionCorners.top()*ratioSize*ratioWindow,
3000         (viewSize.width()-1)*ratioSize,
3001         (viewSize.height()-1)*ratioSize)
3002         );
3003 }
3004
3005 void DefaultViewPort::drawInstructions(QPainter *painter)
3006 {
3007     QFontMetrics metrics = QFontMetrics(font());
3008     int border = qMax(4, metrics.leading());
3009
3010     QRect qrect = metrics.boundingRect(0, 0, width() - 2*border, int(height()*0.125),
3011         Qt::AlignCenter | Qt::TextWordWrap, infoText);
3012     painter->setRenderHint(QPainter::TextAntialiasing);
3013     painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border),
3014         QColor(0, 0, 0, 127));
3015     painter->setPen(Qt::white);
3016     painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border),
3017         QColor(0, 0, 0, 127));
3018
3019     painter->drawText((width() - qrect.width())/2, border,
3020         qrect.width(), qrect.height(),
3021         Qt::AlignCenter | Qt::TextWordWrap, infoText);
3022 }
3023
3024
3025 void DefaultViewPort::setSize(QSize /*size_*/)
3026 {
3027 }
3028
3029
3030 //////////////////////////////////////////////////////
3031 // OpenGlViewPort
3032
3033 #ifdef HAVE_QT_OPENGL
3034
3035 OpenGlViewPort::OpenGlViewPort(QWidget* _parent) : QGLWidget(_parent), size(-1, -1)
3036 {
3037     mouseCallback = 0;
3038     mouseData = 0;
3039
3040     glDrawCallback = 0;
3041     glDrawData = 0;
3042 }
3043
3044 OpenGlViewPort::~OpenGlViewPort()
3045 {
3046 }
3047
3048 QWidget* OpenGlViewPort::getWidget()
3049 {
3050     return this;
3051 }
3052
3053 void OpenGlViewPort::setMouseCallBack(CvMouseCallback callback, void* param)
3054 {
3055     mouseCallback = callback;
3056     mouseData = param;
3057 }
3058
3059 void OpenGlViewPort::writeSettings(QSettings& /*settings*/)
3060 {
3061 }
3062
3063 void OpenGlViewPort::readSettings(QSettings& /*settings*/)
3064 {
3065 }
3066
3067 double OpenGlViewPort::getRatio()
3068 {
3069     return (double)width() / height();
3070 }
3071
3072 void OpenGlViewPort::setRatio(int /*flags*/)
3073 {
3074 }
3075
3076 void OpenGlViewPort::updateImage(const CvArr* /*arr*/)
3077 {
3078 }
3079
3080 void OpenGlViewPort::startDisplayInfo(QString /*text*/, int /*delayms*/)
3081 {
3082 }
3083
3084 void OpenGlViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata)
3085 {
3086     glDrawCallback = callback;
3087     glDrawData = userdata;
3088 }
3089
3090 void OpenGlViewPort::makeCurrentOpenGlContext()
3091 {
3092     makeCurrent();
3093 }
3094
3095 void OpenGlViewPort::updateGl()
3096 {
3097     QGLWidget::updateGL();
3098 }
3099
3100 void OpenGlViewPort::initializeGL()
3101 {
3102     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
3103 }
3104
3105 void OpenGlViewPort::resizeGL(int w, int h)
3106 {
3107     glViewport(0, 0, w, h);
3108 }
3109
3110 void OpenGlViewPort::paintGL()
3111 {
3112     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3113
3114     if (glDrawCallback)
3115         glDrawCallback(glDrawData);
3116 }
3117
3118 void OpenGlViewPort::mousePressEvent(QMouseEvent* evnt)
3119 {
3120     int cv_event = -1, flags = 0;
3121     QPoint pt = evnt->pos();
3122
3123     icvmouseHandler(evnt, mouse_down, cv_event, flags);
3124     icvmouseProcessing(QPointF(pt), cv_event, flags);
3125
3126     QGLWidget::mousePressEvent(evnt);
3127 }
3128
3129
3130 void OpenGlViewPort::mouseReleaseEvent(QMouseEvent* evnt)
3131 {
3132     int cv_event = -1, flags = 0;
3133     QPoint pt = evnt->pos();
3134
3135     icvmouseHandler(evnt, mouse_up, cv_event, flags);
3136     icvmouseProcessing(QPointF(pt), cv_event, flags);
3137
3138     QGLWidget::mouseReleaseEvent(evnt);
3139 }
3140
3141
3142 void OpenGlViewPort::mouseDoubleClickEvent(QMouseEvent* evnt)
3143 {
3144     int cv_event = -1, flags = 0;
3145     QPoint pt = evnt->pos();
3146
3147     icvmouseHandler(evnt, mouse_dbclick, cv_event, flags);
3148     icvmouseProcessing(QPointF(pt), cv_event, flags);
3149
3150     QGLWidget::mouseDoubleClickEvent(evnt);
3151 }
3152
3153
3154 void OpenGlViewPort::mouseMoveEvent(QMouseEvent* evnt)
3155 {
3156     int cv_event = CV_EVENT_MOUSEMOVE, flags = 0;
3157     QPoint pt = evnt->pos();
3158
3159     //icvmouseHandler: pass parameters for cv_event, flags
3160     icvmouseHandler(evnt, mouse_move, cv_event, flags);
3161     icvmouseProcessing(QPointF(pt), cv_event, flags);
3162
3163     QGLWidget::mouseMoveEvent(evnt);
3164 }
3165
3166 void OpenGlViewPort::icvmouseHandler(QMouseEvent* evnt, type_mouse_event category, int& cv_event, int& flags)
3167 {
3168     Qt::KeyboardModifiers modifiers = evnt->modifiers();
3169     Qt::MouseButtons buttons = evnt->buttons();
3170
3171     flags = 0;
3172     if (modifiers & Qt::ShiftModifier)
3173         flags |= CV_EVENT_FLAG_SHIFTKEY;
3174     if (modifiers & Qt::ControlModifier)
3175         flags |= CV_EVENT_FLAG_CTRLKEY;
3176     if (modifiers & Qt::AltModifier)
3177         flags |= CV_EVENT_FLAG_ALTKEY;
3178
3179     if (buttons & Qt::LeftButton)
3180         flags |= CV_EVENT_FLAG_LBUTTON;
3181     if (buttons & Qt::RightButton)
3182         flags |= CV_EVENT_FLAG_RBUTTON;
3183     if (buttons & Qt::MidButton)
3184         flags |= CV_EVENT_FLAG_MBUTTON;
3185
3186     cv_event = CV_EVENT_MOUSEMOVE;
3187     switch (evnt->button())
3188     {
3189     case Qt::LeftButton:
3190         cv_event = tableMouseButtons[category][0];
3191         flags |= CV_EVENT_FLAG_LBUTTON;
3192         break;
3193
3194     case Qt::RightButton:
3195         cv_event = tableMouseButtons[category][1];
3196         flags |= CV_EVENT_FLAG_RBUTTON;
3197         break;
3198
3199     case Qt::MidButton:
3200         cv_event = tableMouseButtons[category][2];
3201         flags |= CV_EVENT_FLAG_MBUTTON;
3202         break;
3203
3204     default:
3205         ;
3206     }
3207 }
3208
3209
3210 void OpenGlViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
3211 {
3212     if (mouseCallback)
3213         mouseCallback(cv_event, pt.x(), pt.y(), flags, mouseData);
3214 }
3215
3216
3217 QSize OpenGlViewPort::sizeHint() const
3218 {
3219     if (size.width() > 0 && size.height() > 0)
3220         return size;
3221
3222     return QGLWidget::sizeHint();
3223 }
3224
3225 void OpenGlViewPort::setSize(QSize size_)
3226 {
3227     size = size_;
3228     updateGeometry();
3229 }
3230
3231 #endif
3232
3233 #endif // HAVE_QT