2efee3c94720354b679f3a40004c446666bf07e1
[platform/upstream/opencv.git] / modules / highgui / src / window_w32.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "precomp.hpp"
43
44 using namespace cv;
45
46 #include <windowsx.h> // required for GET_X_LPARAM() and GET_Y_LPARAM() macros
47
48 #if defined _WIN32
49
50 #ifdef __GNUC__
51 #  pragma GCC diagnostic ignored "-Wmissing-declarations"
52 #endif
53
54 #if (_WIN32_IE < 0x0500)
55 #pragma message("WARNING: Win32 UI needs to be compiled with _WIN32_IE >= 0x0500 (_WIN32_IE_IE50)")
56 #define _WIN32_IE 0x0500
57 #endif
58
59 #include <commctrl.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stdio.h>
63 #include <assert.h>
64
65 #ifdef HAVE_OPENGL
66 #include <memory>
67 #include <algorithm>
68 #include <vector>
69 #include <functional>
70 #include "opencv2/highgui.hpp"
71 #include <GL/gl.h>
72 #include "opencv2/core/opengl.hpp"
73 #endif
74
75 static const char* trackbar_text =
76 "                                                                                             ";
77
78 #if defined _M_X64 || defined __x86_64
79
80 #define icvGetWindowLongPtr GetWindowLongPtr
81 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
82 #define icvGetClassLongPtr  GetClassLongPtr
83
84 #define CV_USERDATA GWLP_USERDATA
85 #define CV_WNDPROC GWLP_WNDPROC
86 #define CV_HCURSOR GCLP_HCURSOR
87 #define CV_HBRBACKGROUND GCLP_HBRBACKGROUND
88
89 #else
90
91 #define icvGetWindowLongPtr GetWindowLong
92 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
93 #define icvGetClassLongPtr GetClassLong
94
95 #define CV_USERDATA GWL_USERDATA
96 #define CV_WNDPROC GWL_WNDPROC
97 #define CV_HCURSOR GCL_HCURSOR
98 #define CV_HBRBACKGROUND GCL_HBRBACKGROUND
99
100 #endif
101
102 #ifndef WM_MOUSEHWHEEL
103     #define WM_MOUSEHWHEEL 0x020E
104 #endif
105
106 static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
107 {
108     assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
109
110     BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
111
112     memset( bmih, 0, sizeof(*bmih));
113     bmih->biSize = sizeof(BITMAPINFOHEADER);
114     bmih->biWidth = width;
115     bmih->biHeight = origin ? abs(height) : -abs(height);
116     bmih->biPlanes = 1;
117     bmih->biBitCount = (unsigned short)bpp;
118     bmih->biCompression = BI_RGB;
119
120     if( bpp == 8 )
121     {
122         RGBQUAD* palette = bmi->bmiColors;
123         int i;
124         for( i = 0; i < 256; i++ )
125         {
126             palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
127             palette[i].rgbReserved = 0;
128         }
129     }
130 }
131
132 struct CvWindow;
133
134 typedef struct CvTrackbar
135 {
136     int signature;
137     HWND hwnd;
138     char* name;
139     CvTrackbar* next;
140     CvWindow* parent;
141     HWND buddy;
142     int* data;
143     int pos;
144     int maxval;
145     int minval;
146     void (*notify)(int);
147     void (*notify2)(int, void*);
148     void* userdata;
149     int id;
150 }
151 CvTrackbar;
152
153
154 typedef struct CvWindow
155 {
156     int signature;
157     HWND hwnd;
158     char* name;
159     CvWindow* prev;
160     CvWindow* next;
161     HWND frame;
162
163     HDC dc;
164     HGDIOBJ image;
165     int last_key;
166     int flags;
167     int status;//0 normal, 1 fullscreen (YV)
168
169     CvMouseCallback on_mouse;
170     void* on_mouse_param;
171
172     struct
173     {
174         HWND toolbar;
175         int pos;
176         int rows;
177         WNDPROC toolBarProc;
178         CvTrackbar* first;
179     }
180     toolbar;
181
182     int width;
183     int height;
184
185     // OpenGL support
186
187 #ifdef HAVE_OPENGL
188     bool useGl;
189     HGLRC hGLRC;
190
191     CvOpenGlDrawCallback glDrawCallback;
192     void* glDrawData;
193 #endif
194 }
195 CvWindow;
196
197 #define HG_BUDDY_WIDTH  130
198
199 #ifndef TBIF_SIZE
200     #define TBIF_SIZE  0x40
201 #endif
202
203 #ifndef TB_SETBUTTONINFO
204     #define TB_SETBUTTONINFO (WM_USER + 66)
205 #endif
206
207 #ifndef TBM_GETTOOLTIPS
208     #define TBM_GETTOOLTIPS  (WM_USER + 30)
209 #endif
210
211 static LRESULT CALLBACK HighGUIProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
212 static LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
213 static LRESULT CALLBACK MainWindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
214 static void icvUpdateWindowPos( CvWindow* window );
215
216 static CvWindow* hg_windows = 0;
217
218 typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*);
219 static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
220 static HINSTANCE hg_hinstance = 0;
221
222 static const char* highGUIclassName = "HighGUI class";
223 static const char* mainHighGUIclassName = "Main HighGUI class";
224
225 static void icvCleanupHighgui()
226 {
227     cvDestroyAllWindows();
228     UnregisterClass(highGUIclassName, hg_hinstance);
229     UnregisterClass(mainHighGUIclassName, hg_hinstance);
230 }
231
232 CV_IMPL int cvInitSystem( int, char** )
233 {
234     static int wasInitialized = 0;
235
236     // check initialization status
237     if( !wasInitialized )
238     {
239         // Initialize the stogare
240         hg_windows = 0;
241
242         // Register the class
243         WNDCLASS wndc;
244         wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
245         wndc.lpfnWndProc = WindowProc;
246         wndc.cbClsExtra = 0;
247         wndc.cbWndExtra = 0;
248         wndc.hInstance = hg_hinstance;
249         wndc.lpszClassName = highGUIclassName;
250         wndc.lpszMenuName = highGUIclassName;
251         wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
252         wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
253         wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
254
255         RegisterClass(&wndc);
256
257         wndc.lpszClassName = mainHighGUIclassName;
258         wndc.lpszMenuName = mainHighGUIclassName;
259         wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
260         wndc.lpfnWndProc = MainWindowProc;
261
262         RegisterClass(&wndc);
263         atexit( icvCleanupHighgui );
264
265         wasInitialized = 1;
266     }
267
268     setlocale(LC_NUMERIC,"C");
269
270     return 0;
271 }
272
273 CV_IMPL int cvStartWindowThread(){
274     return 0;
275 }
276
277 static CvWindow* icvFindWindowByName( const char* name )
278 {
279     CvWindow* window = hg_windows;
280
281     for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
282         ;
283
284     return window;
285 }
286
287
288 static CvWindow* icvWindowByHWND( HWND hwnd )
289 {
290     CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
291     return window != 0 && hg_windows != 0 &&
292            window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
293 }
294
295
296 static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
297 {
298     CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
299     return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
300            trackbar->hwnd == hwnd ? trackbar : 0;
301 }
302
303
304 static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
305
306 // Window positions saving/loading added by Philip Gruebele.
307 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
308 // Restores the window position from the registry saved position.
309 static void
310 icvLoadWindowPos( const char* name, CvRect& rect )
311 {
312     HKEY hkey;
313     char szKey[1024];
314     strcpy_s( szKey, 1024, icvWindowPosRootKey );
315     strcat_s( szKey, 1024, name );
316
317     rect.x = rect.y = CW_USEDEFAULT;
318     rect.width = rect.height = 320;
319
320     if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
321     {
322         // Yes we are installed.
323         DWORD dwType = 0;
324         DWORD dwSize = sizeof(int);
325
326         RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize);
327         RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize);
328         RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize);
329         RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize);
330
331         // Snap rect into closest monitor in case it falls outside it. // Adi Shavit
332         // set WIN32 RECT to be the loaded size
333         POINT tl_w32 = { rect.x, rect.y };
334         POINT tr_w32 = { rect.x + rect.width, rect.y };
335
336         // find monitor containing top-left and top-right corners, or NULL
337         HMONITOR hMonitor_l = MonitorFromPoint(tl_w32, MONITOR_DEFAULTTONULL);
338         HMONITOR hMonitor_r = MonitorFromPoint(tr_w32, MONITOR_DEFAULTTONULL);
339
340         // if neither are contained - the move window to origin of closest.
341         if (NULL == hMonitor_l && NULL == hMonitor_r)
342         {
343            // find monitor nearest to top-left corner
344            HMONITOR hMonitor_closest = MonitorFromPoint(tl_w32, MONITOR_DEFAULTTONEAREST);
345
346            // get coordinates of nearest monitor
347            MONITORINFO mi;
348            mi.cbSize = sizeof(mi);
349            GetMonitorInfo(hMonitor_closest, &mi);
350
351            rect.x = mi.rcWork.left;
352            rect.y = mi.rcWork.top;
353         }
354
355         if (rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000))
356            rect.width = 100;
357         if (rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000))
358            rect.height = 100;
359
360         RegCloseKey(hkey);
361     }
362 }
363
364
365 // Window positions saving/loading added by Philip Gruebele.
366 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
367 // philipg.  Saves the window position in the registry
368 static void
369 icvSaveWindowPos( const char* name, CvRect rect )
370 {
371     static const DWORD MAX_RECORD_COUNT = 100;
372     HKEY hkey;
373     char szKey[1024];
374     char rootKey[1024];
375     strcpy_s( szKey, 1024, icvWindowPosRootKey );
376     strcat_s( szKey, 1024, name );
377
378     if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
379     {
380         HKEY hroot;
381         DWORD count = 0;
382         FILETIME oldestTime = { UINT_MAX, UINT_MAX };
383         char oldestKey[1024];
384         char currentKey[1024];
385
386         strcpy_s( rootKey, 1024, icvWindowPosRootKey );
387         rootKey[strlen(rootKey)-1] = '\0';
388         if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
389             //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
390             return;
391
392         for(;;)
393         {
394             DWORD csize = sizeof(currentKey);
395             FILETIME accesstime = { 0, 0 };
396             LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
397             if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
398                 break;
399             count++;
400             if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
401                 (oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
402                 oldestTime.dwLowDateTime > accesstime.dwLowDateTime) )
403             {
404                 oldestTime = accesstime;
405                 strcpy_s( oldestKey, 1024, currentKey );
406             }
407         }
408
409         if( count >= MAX_RECORD_COUNT )
410             RegDeleteKey( hroot, oldestKey );
411         RegCloseKey( hroot );
412
413         if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
414             return;
415     }
416     else
417     {
418         RegCloseKey( hkey );
419         if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
420             return;
421     }
422
423     RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x));
424     RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y));
425     RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width));
426     RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height));
427     RegCloseKey(hkey);
428 }
429
430 CvRect cvGetWindowRect_W32(const char* name)
431 {
432     CvRect result = cvRect(-1, -1, -1, -1);
433
434     CV_FUNCNAME( "cvGetWindowRect_W32" );
435
436     __BEGIN__;
437
438     CvWindow* window;
439
440     if (!name)
441         CV_ERROR( CV_StsNullPtr, "NULL name string" );
442     window = icvFindWindowByName( name );
443     if (!window)
444         EXIT; // keep silence here
445
446     RECT rect;
447     GetClientRect(window->hwnd, &rect);
448     {
449     POINT pt = {rect.left, rect.top};
450     ClientToScreen(window->hwnd, &pt);
451     result = cvRect(pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top);
452     }
453     __END__;
454     return result;
455 }
456
457 double cvGetModeWindow_W32(const char* name)//YV
458 {
459     double result = -1;
460
461     CV_FUNCNAME( "cvGetModeWindow_W32" );
462
463     __BEGIN__;
464
465     CvWindow* window;
466
467     if (!name)
468         CV_ERROR( CV_StsNullPtr, "NULL name string" );
469
470     window = icvFindWindowByName( name );
471     if (!window)
472         EXIT; // keep silence here
473
474     result = window->status;
475
476     __END__;
477     return result;
478 }
479
480 void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
481 {
482     CV_FUNCNAME( "cvSetModeWindow_W32" );
483
484     __BEGIN__;
485
486     CvWindow* window;
487
488     if(!name)
489         CV_ERROR( CV_StsNullPtr, "NULL name string" );
490
491     window = icvFindWindowByName( name );
492     if( !window )
493         CV_ERROR( CV_StsNullPtr, "NULL window" );
494
495     if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
496         EXIT;
497
498     {
499         DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE);
500         CvRect position;
501
502         if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
503         {
504             icvLoadWindowPos(window->name,position );
505             SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);
506
507             SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
508             window->status=CV_WINDOW_NORMAL;
509
510             EXIT;
511         }
512
513         if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
514         {
515             //save dimension
516             RECT rect;
517             GetWindowRect(window->frame, &rect);
518             CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top);
519             icvSaveWindowPos(window->name,RectCV );
520
521             //Look at coordinate for fullscreen
522             HMONITOR hMonitor;
523             MONITORINFO mi;
524             hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
525
526             mi.cbSize = sizeof(mi);
527             GetMonitorInfo(hMonitor, &mi);
528
529             //fullscreen
530             position.x=mi.rcMonitor.left;position.y=mi.rcMonitor.top;
531             position.width=mi.rcMonitor.right - mi.rcMonitor.left;position.height=mi.rcMonitor.bottom - mi.rcMonitor.top;
532             SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME);
533
534             SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
535             window->status=CV_WINDOW_FULLSCREEN;
536
537             EXIT;
538         }
539     }
540
541     __END__;
542 }
543
544 double cvGetPropTopmost_W32(const char* name)
545 {
546     double result = -1;
547
548     CV_Assert(name);
549
550     CvWindow* window = icvFindWindowByName(name);
551     if (!window)
552         CV_Error(Error::StsNullPtr, "NULL window");
553
554     LONG style = GetWindowLongA(window->frame, GWL_EXSTYLE); // -20
555     if (!style)
556     {
557         std::ostringstream errorMsg;
558         errorMsg << "window(" << name << "): failed to retrieve extended window style using GetWindowLongA(); error code: " << GetLastError();
559         CV_Error(Error::StsError, errorMsg.str().c_str());
560     }
561
562     result = (style & WS_EX_TOPMOST) == WS_EX_TOPMOST;
563
564     return result;
565 }
566
567 void cvSetPropTopmost_W32(const char* name, const bool topmost)
568 {
569     CV_Assert(name);
570
571     CvWindow* window = icvFindWindowByName(name);
572     if (!window)
573         CV_Error(Error::StsNullPtr, "NULL window");
574
575     HWND flag    = topmost ? HWND_TOPMOST : HWND_TOP;
576     BOOL success = SetWindowPos(window->frame, flag, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
577
578     if (!success)
579     {
580         std::ostringstream errorMsg;
581         errorMsg << "window(" << name << "): error reported by SetWindowPos(" << (topmost ? "HWND_TOPMOST" : "HWND_TOP") << "), error code:  " << GetLastError();
582         CV_Error(Error::StsError, errorMsg.str().c_str());
583     }
584 }
585
586 void cv::setWindowTitle(const String& winname, const String& title)
587 {
588     CvWindow* window = icvFindWindowByName(winname.c_str());
589
590     if (!window)
591     {
592         namedWindow(winname);
593         window = icvFindWindowByName(winname.c_str());
594     }
595
596     if (!window)
597         CV_Error(Error::StsNullPtr, "NULL window");
598
599     if (!SetWindowText(window->frame, title.c_str()))
600         CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", winname.c_str(), title.c_str()));
601 }
602
603 double cvGetPropWindowAutoSize_W32(const char* name)
604 {
605     double result = -1;
606
607     CV_FUNCNAME( "cvSetCloseCallback" );
608
609     __BEGIN__;
610
611     CvWindow* window;
612
613     if (!name)
614         CV_ERROR( CV_StsNullPtr, "NULL name string" );
615
616     window = icvFindWindowByName( name );
617     if (!window)
618         EXIT; // keep silence here
619
620     result = window->flags & CV_WINDOW_AUTOSIZE;
621
622     __END__;
623
624     return result;
625 }
626
627 double cvGetRatioWindow_W32(const char* name)
628 {
629     double result = -1;
630
631     CV_FUNCNAME( "cvGetRatioWindow_W32" );
632
633     __BEGIN__;
634
635     CvWindow* window;
636
637     if (!name)
638         CV_ERROR( CV_StsNullPtr, "NULL name string" );
639
640     window = icvFindWindowByName( name );
641     if (!window)
642         EXIT; // keep silence here
643
644     result = static_cast<double>(window->width) / window->height;
645
646     __END__;
647
648     return result;
649 }
650
651 double cvGetOpenGlProp_W32(const char* name)
652 {
653     double result = -1;
654
655 #ifdef HAVE_OPENGL
656     CV_FUNCNAME( "cvGetOpenGlProp_W32" );
657
658     __BEGIN__;
659
660     CvWindow* window;
661
662     if (!name)
663         CV_ERROR( CV_StsNullPtr, "NULL name string" );
664
665     window = icvFindWindowByName( name );
666     if (!window)
667         EXIT; // keep silence here
668
669     result = window->useGl;
670
671     __END__;
672 #endif
673     CV_UNUSED(name);
674
675     return result;
676 }
677
678 double cvGetPropVisible_W32(const char* name)
679 {
680     double result = -1;
681
682     CV_FUNCNAME( "cvGetPropVisible_W32" );
683
684     __BEGIN__;
685
686     if (!name)
687         CV_ERROR( CV_StsNullPtr, "NULL name string" );
688
689     result = (icvFindWindowByName( name ) != NULL);
690
691     __END__;
692
693     return result;
694 }
695
696
697 // OpenGL support
698
699 #ifdef HAVE_OPENGL
700
701 namespace
702 {
703     void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl)
704     {
705         CV_FUNCNAME( "createGlContext" );
706
707         __BEGIN__;
708
709         useGl = false;
710
711         int PixelFormat;
712
713         static PIXELFORMATDESCRIPTOR pfd =
714         {
715             sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
716             1,                             // Version Number
717             PFD_DRAW_TO_WINDOW |           // Format Must Support Window
718             PFD_SUPPORT_OPENGL |           // Format Must Support OpenGL
719             PFD_DOUBLEBUFFER,              // Must Support Double Buffering
720             PFD_TYPE_RGBA,                 // Request An RGBA Format
721             32,                            // Select Our Color Depth
722             0, 0, 0, 0, 0, 0,              // Color Bits Ignored
723             0,                             // No Alpha Buffer
724             0,                             // Shift Bit Ignored
725             0,                             // No Accumulation Buffer
726             0, 0, 0, 0,                    // Accumulation Bits Ignored
727             32,                            // 32 Bit Z-Buffer (Depth Buffer)
728             0,                             // No Stencil Buffer
729             0,                             // No Auxiliary Buffer
730             PFD_MAIN_PLANE,                // Main Drawing Layer
731             0,                             // Reserved
732             0, 0, 0                        // Layer Masks Ignored
733         };
734
735         hGLDC = GetDC(hWnd);
736         if (!hGLDC)
737             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
738
739         PixelFormat = ChoosePixelFormat(hGLDC, &pfd);
740         if (!PixelFormat)
741             CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" );
742
743         if (!SetPixelFormat(hGLDC, PixelFormat, &pfd))
744             CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" );
745
746         hGLRC = wglCreateContext(hGLDC);
747         if (!hGLRC)
748             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" );
749
750         if (!wglMakeCurrent(hGLDC, hGLRC))
751             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
752
753         useGl = true;
754
755         __END__;
756     }
757
758     void releaseGlContext(CvWindow* window)
759     {
760         //CV_FUNCNAME( "releaseGlContext" );
761
762         __BEGIN__;
763
764         if (window->hGLRC)
765         {
766             wglDeleteContext(window->hGLRC);
767             window->hGLRC = NULL;
768         }
769
770         if (window->dc)
771         {
772             ReleaseDC(window->hwnd, window->dc);
773             window->dc = NULL;
774         }
775
776         window->useGl = false;
777
778         __END__;
779     }
780
781     void drawGl(CvWindow* window)
782     {
783         CV_FUNCNAME( "drawGl" );
784
785         __BEGIN__;
786
787         if (!wglMakeCurrent(window->dc, window->hGLRC))
788             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
789
790         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
791
792         if (window->glDrawCallback)
793             window->glDrawCallback(window->glDrawData);
794
795         if (!SwapBuffers(window->dc))
796             CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" );
797
798         __END__;
799     }
800
801     void resizeGl(CvWindow* window)
802     {
803         CV_FUNCNAME( "resizeGl" );
804
805         __BEGIN__;
806
807         if (!wglMakeCurrent(window->dc, window->hGLRC))
808             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
809
810         glViewport(0, 0, window->width, window->height);
811
812         __END__;
813     }
814 }
815
816 #endif // HAVE_OPENGL
817
818
819 CV_IMPL int cvNamedWindow( const char* name, int flags )
820 {
821     int result = 0;
822     CV_FUNCNAME( "cvNamedWindow" );
823
824     __BEGIN__;
825
826     HWND hWnd, mainhWnd;
827     CvWindow* window;
828     DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
829     int len;
830     CvRect rect;
831 #ifdef HAVE_OPENGL
832     bool useGl;
833     HDC hGLDC;
834     HGLRC hGLRC;
835 #endif
836
837     cvInitSystem(0,0);
838
839     if( !name )
840         CV_ERROR( CV_StsNullPtr, "NULL name string" );
841
842     // Check the name in the storage
843     window = icvFindWindowByName( name );
844     if (window != 0)
845     {
846         result = 1;
847         EXIT;
848     }
849
850     if( !(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
851        defStyle |= WS_SIZEBOX;
852
853 #ifdef HAVE_OPENGL
854     if (flags & CV_WINDOW_OPENGL)
855         defStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
856 #endif
857
858     icvLoadWindowPos( name, rect );
859
860     mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
861                              rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
862     if( !mainhWnd )
863         CV_ERROR( CV_StsError, "Frame window can not be created" );
864
865     ShowWindow(mainhWnd, SW_SHOW);
866
867     //YV- remove one border by changing the style
868     hWnd = CreateWindow("HighGUI class", "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
869     if( !hWnd )
870         CV_ERROR( CV_StsError, "Frame window can not be created" );
871
872 #ifndef HAVE_OPENGL
873     if (flags & CV_WINDOW_OPENGL)
874         CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
875 #else
876     useGl = false;
877     hGLDC = 0;
878     hGLRC = 0;
879
880     if (flags & CV_WINDOW_OPENGL)
881         createGlContext(hWnd, hGLDC, hGLRC, useGl);
882 #endif
883
884     ShowWindow(hWnd, SW_SHOW);
885
886     len = (int)strlen(name);
887     CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
888
889     window->signature = CV_WINDOW_MAGIC_VAL;
890     window->hwnd = hWnd;
891     window->frame = mainhWnd;
892     window->name = (char*)(window + 1);
893     memcpy( window->name, name, len + 1 );
894     window->flags = flags;
895     window->image = 0;
896
897 #ifndef HAVE_OPENGL
898     window->dc = CreateCompatibleDC(0);
899 #else
900     if (!useGl)
901     {
902         window->dc = CreateCompatibleDC(0);
903         window->hGLRC = 0;
904         window->useGl = false;
905     }
906     else
907     {
908         window->dc = hGLDC;
909         window->hGLRC = hGLRC;
910         window->useGl = true;
911     }
912
913     window->glDrawCallback = 0;
914     window->glDrawData = 0;
915 #endif
916
917     window->last_key = 0;
918     window->status = CV_WINDOW_NORMAL;//YV
919
920     window->on_mouse = 0;
921     window->on_mouse_param = 0;
922
923     memset( &window->toolbar, 0, sizeof(window->toolbar));
924
925     window->next = hg_windows;
926     window->prev = 0;
927     if( hg_windows )
928         hg_windows->prev = window;
929     hg_windows = window;
930     icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
931     icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
932
933     // Recalculate window pos
934     icvUpdateWindowPos( window );
935
936     result = 1;
937     __END__;
938
939     return result;
940 }
941
942 #ifdef HAVE_OPENGL
943
944 CV_IMPL void cvSetOpenGlContext(const char* name)
945 {
946     CV_FUNCNAME( "cvSetOpenGlContext" );
947
948     __BEGIN__;
949
950     CvWindow* window;
951
952     if(!name)
953         CV_ERROR( CV_StsNullPtr, "NULL name string" );
954
955     window = icvFindWindowByName( name );
956     if (!window)
957         CV_ERROR( CV_StsNullPtr, "NULL window" );
958
959     if (!window->useGl)
960         CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
961
962     if (!wglMakeCurrent(window->dc, window->hGLRC))
963         CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
964
965     __END__;
966 }
967
968 CV_IMPL void cvUpdateWindow(const char* name)
969 {
970     CV_FUNCNAME( "cvUpdateWindow" );
971
972     __BEGIN__;
973
974     CvWindow* window;
975
976     if (!name)
977         CV_ERROR( CV_StsNullPtr, "NULL name string" );
978
979     window = icvFindWindowByName( name );
980     if (!window)
981         EXIT;
982
983     InvalidateRect(window->hwnd, 0, 0);
984
985     __END__;
986 }
987
988 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
989 {
990     CV_FUNCNAME( "cvCreateOpenGLCallback" );
991
992     __BEGIN__;
993
994     CvWindow* window;
995
996     if(!name)
997         CV_ERROR( CV_StsNullPtr, "NULL name string" );
998
999     window = icvFindWindowByName( name );
1000     if( !window )
1001         EXIT;
1002
1003     if (!window->useGl)
1004         CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
1005
1006     window->glDrawCallback = callback;
1007     window->glDrawData = userdata;
1008
1009     __END__;
1010 }
1011
1012 #endif // HAVE_OPENGL
1013
1014 static void icvRemoveWindow( CvWindow* window )
1015 {
1016     CvTrackbar* trackbar = NULL;
1017     RECT wrect={0,0,0,0};
1018
1019 #ifdef HAVE_OPENGL
1020     if (window->useGl)
1021         releaseGlContext(window);
1022 #endif
1023
1024     if( window->frame )
1025         GetWindowRect( window->frame, &wrect );
1026     if( window->name )
1027         icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
1028             wrect.right-wrect.left, wrect.bottom-wrect.top) );
1029
1030     if( window->hwnd )
1031         icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
1032     if( window->frame )
1033         icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
1034
1035     if( window->toolbar.toolbar )
1036         icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0);
1037
1038     if( window->prev )
1039         window->prev->next = window->next;
1040     else
1041         hg_windows = window->next;
1042
1043     if( window->next )
1044         window->next->prev = window->prev;
1045
1046     window->prev = window->next = 0;
1047
1048     if( window->dc && window->image )
1049         DeleteObject(SelectObject(window->dc,window->image));
1050
1051     if( window->dc )
1052         DeleteDC(window->dc);
1053
1054     for( trackbar = window->toolbar.first; trackbar != 0; )
1055     {
1056         CvTrackbar* next = trackbar->next;
1057         if( trackbar->hwnd )
1058         {
1059             icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
1060             cvFree( &trackbar );
1061         }
1062         trackbar = next;
1063     }
1064
1065     cvFree( &window );
1066 }
1067
1068
1069 CV_IMPL void cvDestroyWindow( const char* name )
1070 {
1071     CV_FUNCNAME( "cvDestroyWindow" );
1072
1073     __BEGIN__;
1074
1075     CvWindow* window;
1076     HWND mainhWnd;
1077
1078     if(!name)
1079         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1080
1081     window = icvFindWindowByName( name );
1082     if( !window )
1083         EXIT;
1084
1085     mainhWnd = window->frame;
1086
1087     SendMessage(window->hwnd, WM_CLOSE, 0, 0);
1088     SendMessage( mainhWnd, WM_CLOSE, 0, 0);
1089     // Do NOT call _remove_window -- CvWindow list will be updated automatically ...
1090
1091     __END__;
1092 }
1093
1094
1095 static void icvScreenToClient( HWND hwnd, RECT* rect )
1096 {
1097     POINT p;
1098     p.x = rect->left;
1099     p.y = rect->top;
1100     ScreenToClient(hwnd, &p);
1101     OffsetRect( rect, p.x - rect->left, p.y - rect->top );
1102 }
1103
1104
1105 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
1106 static RECT icvCalcWindowRect( CvWindow* window )
1107 {
1108     const int gutter = 1;
1109     RECT crect, trect, rect;
1110
1111     assert(window);
1112
1113     GetClientRect(window->frame, &crect);
1114     if(window->toolbar.toolbar)
1115     {
1116         GetWindowRect(window->toolbar.toolbar, &trect);
1117         icvScreenToClient(window->frame, &trect);
1118         SubtractRect( &rect, &crect, &trect);
1119     }
1120     else
1121         rect = crect;
1122
1123     rect.top += gutter;
1124     rect.left += gutter;
1125     rect.bottom -= gutter;
1126     rect.right -= gutter;
1127
1128     return rect;
1129 }
1130
1131 // returns TRUE if there is a problem such as ERROR_IO_PENDING.
1132 static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
1133 {
1134     BITMAP bmp;
1135     GdiFlush();
1136     HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
1137     if( size )
1138         size->cx = size->cy = 0;
1139     if( data )
1140         *data = 0;
1141
1142     if (h == NULL)
1143         return true;
1144     if (GetObject(h, sizeof(bmp), &bmp) == 0)
1145         return true;
1146
1147     if( size )
1148     {
1149         size->cx = abs(bmp.bmWidth);
1150         size->cy = abs(bmp.bmHeight);
1151     }
1152
1153     if( channels )
1154         *channels = bmp.bmBitsPixel/8;
1155
1156     if( data )
1157         *data = bmp.bmBits;
1158
1159     return false;
1160 }
1161
1162
1163 static void icvUpdateWindowPos( CvWindow* window )
1164 {
1165     RECT rect;
1166     assert(window);
1167
1168     if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
1169     {
1170         int i;
1171         SIZE size = {0,0};
1172         icvGetBitmapData( window, &size, 0, 0 );
1173
1174         // Repeat two times because after the first resizing of the mainhWnd window
1175         // toolbar may resize too
1176         for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
1177         {
1178             RECT rmw, rw = icvCalcWindowRect(window );
1179             MoveWindow(window->hwnd, rw.left, rw.top,
1180                 rw.right - rw.left, rw.bottom - rw.top, FALSE);
1181             GetClientRect(window->hwnd, &rw);
1182             GetWindowRect(window->frame, &rmw);
1183             // Resize the mainhWnd window in order to make the bitmap fit into the child window
1184             MoveWindow(window->frame, rmw.left, rmw.top,
1185                 size.cx + (rmw.right - rmw.left) - (rw.right - rw.left),
1186                 size.cy + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE );
1187         }
1188     }
1189
1190     rect = icvCalcWindowRect(window);
1191     MoveWindow(window->hwnd, rect.left, rect.top,
1192                rect.right - rect.left,
1193                rect.bottom - rect.top, TRUE );
1194 }
1195
1196 CV_IMPL void
1197 cvShowImage( const char* name, const CvArr* arr )
1198 {
1199     CV_FUNCNAME( "cvShowImage" );
1200
1201     __BEGIN__;
1202
1203     CvWindow* window;
1204     SIZE size = { 0, 0 };
1205     int channels = 0;
1206     void* dst_ptr = 0;
1207     const int channels0 = 3;
1208     int origin = 0;
1209     CvMat stub, dst, *image;
1210     bool changed_size = false; // philipg
1211
1212     if( !name )
1213         CV_ERROR( CV_StsNullPtr, "NULL name" );
1214
1215     window = icvFindWindowByName(name);
1216     if(!window)
1217     {
1218         cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
1219         window = icvFindWindowByName(name);
1220     }
1221
1222     if( !window || !arr )
1223         EXIT; // keep silence here.
1224
1225     if( CV_IS_IMAGE_HDR( arr ))
1226         origin = ((IplImage*)arr)->origin;
1227
1228     CV_CALL( image = cvGetMat( arr, &stub ));
1229
1230 #ifdef HAVE_OPENGL
1231     if (window->useGl)
1232     {
1233         cv::imshow(name, cv::cvarrToMat(image));
1234         return;
1235     }
1236 #endif
1237
1238     if (window->image)
1239         // if there is something wrong with these system calls, we cannot display image...
1240         if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
1241             return;
1242
1243     if( size.cx != image->width || size.cy != image->height || channels != channels0 )
1244     {
1245         changed_size = true;
1246
1247         uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
1248         BITMAPINFO* binfo = (BITMAPINFO*)buffer;
1249
1250         DeleteObject( SelectObject( window->dc, window->image ));
1251         window->image = 0;
1252
1253         size.cx = image->width;
1254         size.cy = image->height;
1255         channels = channels0;
1256
1257         FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
1258
1259         window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
1260                                       DIB_RGB_COLORS, &dst_ptr, 0, 0));
1261     }
1262
1263     cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3,
1264                      dst_ptr, (size.cx * channels + 3) & -4 );
1265     cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
1266
1267     // only resize window if needed
1268     if (changed_size)
1269         icvUpdateWindowPos(window);
1270     InvalidateRect(window->hwnd, 0, 0);
1271     // philipg: this is not needed and just slows things down
1272     //    UpdateWindow(window->hwnd);
1273
1274     __END__;
1275 }
1276
1277 #if 0
1278 CV_IMPL void
1279 cvShowImageHWND(HWND w_hWnd, const CvArr* arr)
1280 {
1281     CV_FUNCNAME( "cvShowImageHWND" );
1282
1283     __BEGIN__;
1284
1285     SIZE size = { 0, 0 };
1286     int channels = 0;
1287     void* dst_ptr = 0;
1288     const int channels0 = 3;
1289     int origin = 0;
1290     CvMat stub, dst, *image;
1291     bool changed_size = false;
1292     BITMAPINFO tempbinfo;
1293     HDC hdc = NULL;
1294
1295     if( !arr )
1296         EXIT;
1297     if( !w_hWnd )
1298         EXIT;
1299
1300     hdc = GetDC(w_hWnd);
1301
1302     if( CV_IS_IMAGE_HDR( arr ) )
1303         origin = ((IplImage*)arr)->origin;
1304
1305     CV_CALL( image = cvGetMat( arr, &stub ) );
1306
1307     if ( hdc )
1308     {
1309             //GetBitmapData
1310             BITMAP bmp;
1311             GdiFlush();
1312             HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );
1313
1314             if (h == NULL)
1315             EXIT;
1316             if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
1317             EXIT;
1318
1319             channels = bmp.bmBitsPixel/8;
1320             dst_ptr = bmp.bmBits;
1321      }
1322
1323     if( size.cx != image->width || size.cy != image->height || channels != channels0 )
1324     {
1325         changed_size = true;
1326
1327         uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
1328         BITMAPINFO* binfo = (BITMAPINFO*)buffer;
1329
1330         BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
1331                 CV_Assert( FALSE != bDeleteObj );
1332
1333         size.cx = image->width;
1334         size.cy = image->height;
1335         channels = channels0;
1336
1337         FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
1338
1339         SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
1340     }
1341
1342     cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 );
1343     cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
1344
1345     // Image stretching to fit the window
1346     RECT rect;
1347     GetClientRect(w_hWnd, &rect);
1348     StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, &tempbinfo, DIB_RGB_COLORS, SRCCOPY );
1349
1350     // ony resize window if needed
1351     InvalidateRect(w_hWnd, 0, 0);
1352
1353     __END__;
1354 }
1355 #endif
1356
1357 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1358 {
1359     CV_FUNCNAME( "cvResizeWindow" );
1360
1361     __BEGIN__;
1362
1363     int i;
1364     CvWindow* window;
1365     RECT rmw, rw, rect;
1366
1367     if( !name )
1368         CV_ERROR( CV_StsNullPtr, "NULL name" );
1369
1370     window = icvFindWindowByName(name);
1371     if(!window)
1372         EXIT;
1373
1374     // Repeat two times because after the first resizing of the mainhWnd window
1375     // toolbar may resize too
1376     for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
1377     {
1378         rw = icvCalcWindowRect(window);
1379         MoveWindow(window->hwnd, rw.left, rw.top,
1380             rw.right - rw.left, rw.bottom - rw.top, FALSE);
1381         GetClientRect(window->hwnd, &rw);
1382         GetWindowRect(window->frame, &rmw);
1383         // Resize the mainhWnd window in order to make the bitmap fit into the child window
1384         MoveWindow(window->frame, rmw.left, rmw.top,
1385             width  + (rmw.right - rmw.left) - (rw.right - rw.left),
1386             height + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE);
1387     }
1388
1389     rect = icvCalcWindowRect(window);
1390     MoveWindow(window->hwnd, rect.left, rect.top,
1391         rect.right - rect.left, rect.bottom - rect.top, TRUE);
1392
1393     __END__;
1394 }
1395
1396
1397 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1398 {
1399     CV_FUNCNAME( "cvMoveWindow" );
1400
1401     __BEGIN__;
1402
1403     CvWindow* window;
1404     RECT rect;
1405
1406     if( !name )
1407         CV_ERROR( CV_StsNullPtr, "NULL name" );
1408
1409     window = icvFindWindowByName(name);
1410     if(!window)
1411         EXIT;
1412
1413     GetWindowRect( window->frame, &rect );
1414     MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
1415
1416     __END__;
1417 }
1418
1419
1420 static LRESULT CALLBACK
1421 MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1422 {
1423     CvWindow* window = icvWindowByHWND( hwnd );
1424     if( !window )
1425         return DefWindowProc(hwnd, uMsg, wParam, lParam);
1426
1427     switch(uMsg)
1428     {
1429     case WM_COPY:
1430         ::SendMessage(window->hwnd, uMsg, wParam, lParam);
1431         break;
1432
1433     case WM_DESTROY:
1434
1435         icvRemoveWindow(window);
1436         // Do nothing!!!
1437         //PostQuitMessage(0);
1438         break;
1439
1440     case WM_GETMINMAXINFO:
1441         if( !(window->flags & CV_WINDOW_AUTOSIZE) )
1442         {
1443             MINMAXINFO* minmax = (MINMAXINFO*)lParam;
1444             RECT rect;
1445             LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);
1446
1447             minmax->ptMinTrackSize.y = 100;
1448             minmax->ptMinTrackSize.x = 100;
1449
1450             if( window->toolbar.first )
1451             {
1452                 GetWindowRect( window->toolbar.first->hwnd, &rect );
1453                 minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
1454                 minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
1455             }
1456             return retval;
1457         }
1458         break;
1459
1460     case WM_WINDOWPOSCHANGED:
1461         {
1462             WINDOWPOS* pos = (WINDOWPOS*)lParam;
1463
1464             // Update the toolbar pos/size
1465             if(window->toolbar.toolbar)
1466             {
1467                 RECT rect;
1468                 GetWindowRect(window->toolbar.toolbar, &rect);
1469                 MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
1470             }
1471
1472             if(!(window->flags & CV_WINDOW_AUTOSIZE))
1473                 icvUpdateWindowPos(window);
1474
1475             break;
1476         }
1477
1478     case WM_WINDOWPOSCHANGING:
1479        {
1480           // Snap window to screen edges with multi-monitor support. // Adi Shavit
1481           LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
1482
1483           RECT rect;
1484           GetWindowRect(window->frame, &rect);
1485
1486           HMONITOR hMonitor;
1487           hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
1488
1489           MONITORINFO mi;
1490           mi.cbSize = sizeof(mi);
1491           GetMonitorInfo(hMonitor, &mi);
1492
1493           const int SNAP_DISTANCE = 15;
1494
1495           if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
1496              pos->x = mi.rcMonitor.left;               // snap to left edge
1497           else
1498              if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
1499                 pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge
1500
1501           if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
1502              pos->y = mi.rcMonitor.top;                 // snap to top edge
1503           else
1504              if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
1505                 pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
1506        }
1507
1508     case WM_ACTIVATE:
1509         if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
1510             SetFocus(window->hwnd);
1511         break;
1512
1513     case WM_MOUSEWHEEL:
1514     case WM_MOUSEHWHEEL:
1515        if( window->on_mouse )
1516        {
1517           int flags = (wParam & MK_LBUTTON      ? CV_EVENT_FLAG_LBUTTON  : 0)|
1518                       (wParam & MK_RBUTTON      ? CV_EVENT_FLAG_RBUTTON  : 0)|
1519                       (wParam & MK_MBUTTON      ? CV_EVENT_FLAG_MBUTTON  : 0)|
1520                       (wParam & MK_CONTROL      ? CV_EVENT_FLAG_CTRLKEY  : 0)|
1521                       (wParam & MK_SHIFT        ? CV_EVENT_FLAG_SHIFTKEY : 0)|
1522                       (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY   : 0);
1523           int event = (uMsg == WM_MOUSEWHEEL    ? CV_EVENT_MOUSEWHEEL    : CV_EVENT_MOUSEHWHEEL);
1524
1525           // Set the wheel delta of mouse wheel to be in the upper word of 'event'
1526           int delta = GET_WHEEL_DELTA_WPARAM(wParam);
1527           flags |= (delta << 16);
1528
1529           POINT pt;
1530           pt.x = GET_X_LPARAM( lParam );
1531           pt.y = GET_Y_LPARAM( lParam );
1532           ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates.
1533
1534           RECT rect;
1535           GetClientRect( window->hwnd, &rect );
1536
1537           SIZE size = {0,0};
1538 #ifdef HAVE_OPENGL
1539           if (window->useGl)
1540           {
1541               cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window->glDrawData);
1542               size.cx = texObj->cols();
1543               size.cy = texObj->rows();
1544           }
1545           else
1546           {
1547               icvGetBitmapData(window, &size, 0, 0);
1548           }
1549 #else
1550           icvGetBitmapData(window, &size, 0, 0);
1551 #endif
1552
1553           window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
1554                                    pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
1555                                    window->on_mouse_param );
1556        }
1557        break;
1558
1559     case WM_ERASEBKGND:
1560         {
1561             RECT cr, tr, wrc;
1562             HRGN rgn, rgn1, rgn2;
1563             int ret;
1564             HDC hdc = (HDC)wParam;
1565             GetWindowRect(window->hwnd, &cr);
1566             icvScreenToClient(window->frame, &cr);
1567             if(window->toolbar.toolbar)
1568             {
1569                 GetWindowRect(window->toolbar.toolbar, &tr);
1570                 icvScreenToClient(window->frame, &tr);
1571             }
1572             else
1573                 tr.left = tr.top = tr.right = tr.bottom = 0;
1574
1575             GetClientRect(window->frame, &wrc);
1576
1577             rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
1578             rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
1579             rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom);
1580             CV_Assert_N(rgn != 0, rgn1 != 0, rgn2 != 0);
1581
1582             ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
1583             ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
1584
1585             if(ret != NULLREGION && ret != ERROR)
1586                 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
1587
1588             DeleteObject(rgn);
1589             DeleteObject(rgn1);
1590             DeleteObject(rgn2);
1591         }
1592         return 1;
1593     }
1594
1595     return DefWindowProc(hwnd, uMsg, wParam, lParam);
1596 }
1597
1598
1599 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1600 {
1601     CvWindow* window = icvWindowByHWND(hwnd);
1602     if( !window )
1603         // This window is not mentioned in HighGUI storage
1604         // Actually, this should be error except for the case of calls to CreateWindow
1605         return DefWindowProc(hwnd, uMsg, wParam, lParam);
1606
1607     // Process the message
1608     switch(uMsg)
1609     {
1610     case WM_COPY:
1611         {
1612             if (!::OpenClipboard(hwnd) )
1613                 break;
1614
1615             HDC hDC       = 0;
1616             HDC memDC     = 0;
1617             HBITMAP memBM = 0;
1618
1619             // We'll use a do-while(0){} scope as a single-run breakable scope
1620             // Upon any error we can jump out of the single-time while scope to clean up the resources.
1621             do
1622             {
1623                 if (!::EmptyClipboard())
1624                     break;
1625
1626                 if(!window->image)
1627                     break;
1628
1629                 // Get window device context
1630                 if (0 == (hDC = ::GetDC(hwnd)))
1631                     break;
1632
1633                 // Create another DC compatible with hDC
1634                 if (0 == (memDC = ::CreateCompatibleDC( hDC )))
1635                     break;
1636
1637                 // Determine the bitmap's dimensions
1638                 int nchannels = 3;
1639                 SIZE size = {0,0};
1640                 icvGetBitmapData( window, &size, &nchannels, 0 );
1641
1642                 // Create bitmap to draw on and it in the new DC
1643                 if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy)))
1644                     break;
1645
1646                 if (!::SelectObject( memDC, memBM ))
1647                     break;
1648
1649                 // Begin drawing to DC
1650                 if (!::SetStretchBltMode(memDC, COLORONCOLOR))
1651                     break;
1652
1653                 RGBQUAD table[256];
1654                 if( 1 == nchannels )
1655                 {
1656                     for(int i = 0; i < 256; ++i)
1657                     {
1658                         table[i].rgbBlue = (unsigned char)i;
1659                         table[i].rgbGreen = (unsigned char)i;
1660                         table[i].rgbRed = (unsigned char)i;
1661                     }
1662                     if (!::SetDIBColorTable(window->dc, 0, 255, table))
1663                         break;
1664                 }
1665
1666                 // The image copied to the clipboard will be in its original size, regardless if the window itself was resized.
1667
1668                 // Render the image to the dc/bitmap (at original size).
1669                 if (!::BitBlt( memDC, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY ))
1670                     break;
1671
1672                 // Finally, set bitmap to clipboard
1673                 ::SetClipboardData(CF_BITMAP, memBM);
1674             } while (0,0); // (0,0) instead of (0) to avoid MSVC compiler warning C4127: "conditional expression is constant"
1675
1676             //////////////////////////////////////////////////////////////////////////
1677             // if handle is allocated (i.e. != 0) then clean-up.
1678             if (memBM) ::DeleteObject(memBM);
1679             if (memDC) ::DeleteDC(memDC);
1680             if (hDC)   ::ReleaseDC(hwnd, hDC);
1681             ::CloseClipboard();
1682             break;
1683         }
1684
1685     case WM_WINDOWPOSCHANGING:
1686         {
1687             LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
1688             RECT rect = icvCalcWindowRect(window);
1689             pos->x = rect.left;
1690             pos->y = rect.top;
1691             pos->cx = rect.right - rect.left;
1692             pos->cy = rect.bottom - rect.top;
1693         }
1694         break;
1695
1696     case WM_LBUTTONDOWN:
1697     case WM_RBUTTONDOWN:
1698     case WM_MBUTTONDOWN:
1699     case WM_LBUTTONDBLCLK:
1700     case WM_RBUTTONDBLCLK:
1701     case WM_MBUTTONDBLCLK:
1702     case WM_LBUTTONUP:
1703     case WM_RBUTTONUP:
1704     case WM_MBUTTONUP:
1705     case WM_MOUSEMOVE:
1706         if( window->on_mouse )
1707         {
1708             POINT pt;
1709
1710             int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
1711                         (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
1712                         (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
1713                         (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
1714                         (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
1715                         (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
1716             int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN :
1717                         uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN :
1718                         uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN :
1719                         uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP :
1720                         uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP :
1721                         uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP :
1722                         uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK :
1723                         uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
1724                         uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
1725                                                    CV_EVENT_MOUSEMOVE;
1726             if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
1727                 SetCapture( hwnd );
1728             if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
1729                 ReleaseCapture();
1730
1731             pt.x = GET_X_LPARAM( lParam );
1732             pt.y = GET_Y_LPARAM( lParam );
1733
1734             if (window->flags & CV_WINDOW_AUTOSIZE)
1735             {
1736                 // As user can't change window size, do not scale window coordinates. Underlying windowing system
1737                 // may prevent full window from being displayed and in this case coordinates should not be scaled.
1738                 window->on_mouse( event, pt.x, pt.y, flags, window->on_mouse_param );
1739             } else {
1740                 // Full window is displayed using different size. Scale coordinates to match underlying positions.
1741                 RECT rect;
1742                 SIZE size = {0, 0};
1743
1744                 GetClientRect( window->hwnd, &rect );
1745
1746 #ifdef HAVE_OPENGL
1747                 if (window->useGl)
1748                 {
1749                     cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window->glDrawData);
1750                     size.cx = texObj->cols();
1751                     size.cy = texObj->rows();
1752                 }
1753                 else
1754                 {
1755                     icvGetBitmapData(window, &size, 0, 0);
1756                 }
1757 #else
1758                 icvGetBitmapData( window, &size, 0, 0 );
1759 #endif
1760
1761                 window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
1762                                          pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
1763                                          window->on_mouse_param );
1764             }
1765         }
1766         break;
1767
1768     case WM_PAINT:
1769         if(window->image != 0)
1770         {
1771             int nchannels = 3;
1772             SIZE size = {0,0};
1773             PAINTSTRUCT paint;
1774             HDC hdc;
1775             RGBQUAD table[256];
1776
1777             // Determine the bitmap's dimensions
1778             icvGetBitmapData( window, &size, &nchannels, 0 );
1779
1780             hdc = BeginPaint(hwnd, &paint);
1781             SetStretchBltMode(hdc, COLORONCOLOR);
1782
1783             if( nchannels == 1 )
1784             {
1785                 int i;
1786                 for(i = 0; i < 256; i++)
1787                 {
1788                     table[i].rgbBlue = (unsigned char)i;
1789                     table[i].rgbGreen = (unsigned char)i;
1790                     table[i].rgbRed = (unsigned char)i;
1791                 }
1792                 SetDIBColorTable(window->dc, 0, 255, table);
1793             }
1794
1795             if(window->flags & CV_WINDOW_AUTOSIZE)
1796             {
1797                 BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
1798             }
1799             else
1800             {
1801                 RECT rect;
1802                 GetClientRect(window->hwnd, &rect);
1803                 StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
1804                             window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
1805             }
1806             //DeleteDC(hdc);
1807             EndPaint(hwnd, &paint);
1808         }
1809 #ifdef HAVE_OPENGL
1810         else if(window->useGl)
1811         {
1812             drawGl(window);
1813             return DefWindowProc(hwnd, uMsg, wParam, lParam);
1814         }
1815 #endif
1816         else
1817         {
1818             return DefWindowProc(hwnd, uMsg, wParam, lParam);
1819         }
1820         return 0;
1821
1822     case WM_ERASEBKGND:
1823         if(window->image)
1824             return 0;
1825         break;
1826
1827     case WM_DESTROY:
1828
1829         icvRemoveWindow(window);
1830         // Do nothing!!!
1831         //PostQuitMessage(0);
1832         break;
1833
1834     case WM_SETCURSOR:
1835         SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
1836         return 0;
1837
1838     case WM_KEYDOWN:
1839         window->last_key = (int)wParam;
1840         return 0;
1841
1842     case WM_SIZE:
1843         window->width = LOWORD(lParam);
1844         window->height = HIWORD(lParam);
1845
1846 #ifdef HAVE_OPENGL
1847         if (window->useGl)
1848             resizeGl(window);
1849 #endif
1850     }
1851
1852     return DefWindowProc(hwnd, uMsg, wParam, lParam);
1853 }
1854
1855
1856 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1857 {
1858     LRESULT ret;
1859
1860     if( hg_on_preprocess )
1861     {
1862         int was_processed = 0;
1863         int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1864         if( was_processed )
1865             return rethg;
1866     }
1867     ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
1868
1869     if(hg_on_postprocess)
1870     {
1871         int was_processed = 0;
1872         int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1873         if( was_processed )
1874             return rethg;
1875     }
1876
1877     return ret;
1878 }
1879
1880
1881 static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
1882 {
1883     const int max_name_len = 10;
1884     const char* suffix = "";
1885     char pos_text[32];
1886     int name_len;
1887
1888     if( trackbar->data )
1889         *trackbar->data = pos;
1890
1891     if( trackbar->pos != pos )
1892     {
1893         trackbar->pos = pos;
1894         if( trackbar->notify2 )
1895             trackbar->notify2(pos, trackbar->userdata);
1896         if( trackbar->notify )
1897             trackbar->notify(pos);
1898
1899         name_len = (int)strlen(trackbar->name);
1900
1901         if( name_len > max_name_len )
1902         {
1903             int start_len = max_name_len*2/3;
1904             int end_len = max_name_len - start_len - 2;
1905             memcpy( pos_text, trackbar->name, start_len );
1906             memcpy( pos_text + start_len, "...", 3 );
1907             memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
1908         }
1909         else
1910         {
1911             memcpy( pos_text, trackbar->name, name_len + 1);
1912         }
1913
1914         sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
1915         SetWindowText( trackbar->buddy, pos_text );
1916     }
1917 }
1918
1919
1920 static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1921 {
1922     CvWindow* window = icvWindowByHWND( hwnd );
1923     if(!window)
1924         return DefWindowProc(hwnd, uMsg, wParam, lParam);
1925
1926     // Control messages processing
1927     switch(uMsg)
1928     {
1929     // Slider processing
1930     case WM_HSCROLL:
1931         {
1932             HWND slider = (HWND)lParam;
1933             int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
1934             CvTrackbar* trackbar = icvTrackbarByHWND( slider );
1935
1936             if( trackbar )
1937             {
1938                 if( trackbar->pos != pos )
1939                     icvUpdateTrackbar( trackbar, pos );
1940             }
1941
1942             SetFocus( window->hwnd );
1943             return 0;
1944         }
1945
1946     case WM_NCCALCSIZE:
1947         {
1948             LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1949             int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
1950
1951             if(window->toolbar.rows != rows)
1952             {
1953                 SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1954                 CvTrackbar* trackbar = window->toolbar.first;
1955
1956                 for( ; trackbar != 0; trackbar = trackbar->next )
1957                 {
1958                     RECT rect;
1959                     SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
1960                                (WPARAM)trackbar->id, (LPARAM)&rect);
1961                     MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
1962                                rect.right - rect.left - HG_BUDDY_WIDTH,
1963                                rect.bottom - rect.top, FALSE);
1964                     MoveWindow(trackbar->buddy, rect.left, rect.top,
1965                                HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
1966                 }
1967                 window->toolbar.rows = rows;
1968             }
1969             return ret;
1970         }
1971     }
1972
1973     return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1974 }
1975
1976
1977 CV_IMPL void
1978 cvDestroyAllWindows(void)
1979 {
1980     CvWindow* window = hg_windows;
1981
1982     while( window )
1983     {
1984         HWND mainhWnd = window->frame;
1985         HWND hwnd = window->hwnd;
1986         window = window->next;
1987
1988         SendMessage( hwnd, WM_CLOSE, 0, 0 );
1989         SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
1990     }
1991 }
1992
1993 static void showSaveDialog(CvWindow* window)
1994 {
1995     if (!window || !window->image)
1996         return;
1997
1998     SIZE sz;
1999     int channels;
2000     void* data;
2001     if (icvGetBitmapData(window, &sz, &channels, &data))
2002         return; // nothing to save
2003
2004     char szFileName[MAX_PATH] = "";
2005     // try to use window title as file name
2006     GetWindowText(window->frame, szFileName, MAX_PATH);
2007
2008     OPENFILENAME ofn;
2009     ZeroMemory(&ofn, sizeof(ofn));
2010 #ifdef OPENFILENAME_SIZE_VERSION_400
2011     // we are not going to use new fields any way
2012     ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
2013 #else
2014     ofn.lStructSize = sizeof(ofn);
2015 #endif
2016     ofn.hwndOwner = window->hwnd;
2017     ofn.lpstrFilter =
2018 #ifdef HAVE_PNG
2019                       "Portable Network Graphics files (*.png)\0*.png\0"
2020 #endif
2021                       "Windows bitmap (*.bmp;*.dib)\0*.bmp;*.dib\0"
2022 #ifdef HAVE_JPEG
2023                       "JPEG files (*.jpeg;*.jpg;*.jpe)\0*.jpeg;*.jpg;*.jpe\0"
2024 #endif
2025 #ifdef HAVE_TIFF
2026                       "TIFF Files (*.tiff;*.tif)\0*.tiff;*.tif\0"
2027 #endif
2028 #ifdef HAVE_JASPER
2029                       "JPEG-2000 files (*.jp2)\0*.jp2\0"
2030 #endif
2031 #ifdef HAVE_WEBP
2032                       "WebP files (*.webp)\0*.webp\0"
2033 #endif
2034                       "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)\0*.pbm;*.pgm;*.ppm;*.pxm;*.pnm\0"
2035 #ifdef HAVE_OPENEXR
2036                       "OpenEXR Image files (*.exr)\0*.exr\0"
2037 #endif
2038                       "Radiance HDR (*.hdr;*.pic)\0*.hdr;*.pic\0"
2039                       "Sun raster files (*.sr;*.ras)\0*.sr;*.ras\0"
2040                       "All Files (*.*)\0*.*\0";
2041     ofn.lpstrFile = szFileName;
2042     ofn.nMaxFile = MAX_PATH;
2043     ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_NOCHANGEDIR;
2044 #ifdef HAVE_PNG
2045     ofn.lpstrDefExt = "png";
2046 #else
2047     ofn.lpstrDefExt = "bmp";
2048 #endif
2049
2050     if (GetSaveFileName(&ofn))
2051     {
2052         cv::Mat tmp;
2053         cv::flip(cv::Mat(sz.cy, sz.cx, CV_8UC(channels), data, (sz.cx * channels + 3) & -4), tmp, 0);
2054         cv::imwrite(szFileName, tmp);
2055     }
2056 }
2057
2058 CV_IMPL int
2059 cvWaitKey( int delay )
2060 {
2061     int64 time0 = cv::getTickCount();
2062     int64 timeEnd = time0 + (int64)(delay * 0.001f * cv::getTickFrequency());
2063
2064     for(;;)
2065     {
2066         CvWindow* window;
2067         MSG message;
2068         int is_processed = 0;
2069
2070         if( (delay <= 0) && hg_windows)
2071             GetMessage(&message, 0, 0, 0);
2072         else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
2073         {
2074             int64 t = cv::getTickCount();
2075             if (t - timeEnd >= 0)
2076                 return -1;  // no messages and no more time
2077             Sleep(1);
2078             continue;
2079         }
2080
2081         for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
2082         {
2083             if( window->hwnd == message.hwnd || window->frame == message.hwnd )
2084             {
2085                 is_processed = 1;
2086                 switch(message.message)
2087                 {
2088                 case WM_DESTROY:
2089                 case WM_CHAR:
2090                     DispatchMessage(&message);
2091                     return (int)message.wParam;
2092
2093                 case WM_SYSKEYDOWN:
2094                     if( message.wParam == VK_F10 )
2095                     {
2096                         is_processed = 1;
2097                         return (int)(message.wParam << 16);
2098                     }
2099                     break;
2100
2101                 case WM_KEYDOWN:
2102                     TranslateMessage(&message);
2103                     if( (message.wParam >= VK_F1 && message.wParam <= VK_F24)       ||
2104                         message.wParam == VK_HOME   || message.wParam == VK_END     ||
2105                         message.wParam == VK_UP     || message.wParam == VK_DOWN    ||
2106                         message.wParam == VK_LEFT   || message.wParam == VK_RIGHT   ||
2107                         message.wParam == VK_INSERT || message.wParam == VK_DELETE  ||
2108                         message.wParam == VK_PRIOR  || message.wParam == VK_NEXT )
2109                     {
2110                         DispatchMessage(&message);
2111                         is_processed = 1;
2112                         return (int)(message.wParam << 16);
2113                     }
2114
2115                     // Intercept Ctrl+C for copy to clipboard
2116                     if ('C' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
2117                         ::SendMessage(message.hwnd, WM_COPY, 0, 0);
2118
2119                     // Intercept Ctrl+S for "save as" dialog
2120                     if ('S' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
2121                         showSaveDialog(window);
2122
2123                 default:
2124                     DispatchMessage(&message);
2125                     is_processed = 1;
2126                     break;
2127                 }
2128             }
2129         }
2130
2131         if( !is_processed )
2132         {
2133             TranslateMessage(&message);
2134             DispatchMessage(&message);
2135         }
2136     }
2137 }
2138
2139
2140 static CvTrackbar*
2141 icvFindTrackbarByName( const CvWindow* window, const char* name )
2142 {
2143     CvTrackbar* trackbar = window->toolbar.first;
2144
2145     for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
2146         ;
2147
2148     return trackbar;
2149 }
2150
2151
2152 static int
2153 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
2154                    int* val, int count, CvTrackbarCallback on_notify,
2155                    CvTrackbarCallback2 on_notify2, void* userdata )
2156 {
2157     int result = 0;
2158
2159     CV_FUNCNAME( "icvCreateTrackbar" );
2160
2161     __BEGIN__;
2162
2163     char slider_name[32];
2164     CvWindow* window = 0;
2165     CvTrackbar* trackbar = 0;
2166     int pos = 0;
2167
2168     if( !window_name || !trackbar_name )
2169         CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
2170
2171     if( count < 0 )
2172         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
2173
2174     window = icvFindWindowByName(window_name);
2175     if( !window )
2176         EXIT;
2177
2178     trackbar = icvFindTrackbarByName(window,trackbar_name);
2179     if( !trackbar )
2180     {
2181         TBBUTTON tbs = {};
2182         TBBUTTONINFO tbis = {};
2183         RECT rect;
2184         int bcount;
2185         int len = (int)strlen( trackbar_name );
2186
2187         // create toolbar if it is not created yet
2188         if( !window->toolbar.toolbar )
2189         {
2190             const int default_height = 30;
2191
2192             // CreateToolbarEx is deprecated and forces linking against Comctl32.lib.
2193             window->toolbar.toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
2194                                         WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE | BTNS_AUTOSIZE | BTNS_BUTTON,
2195                                         0, 0, 0, 0,
2196                                         window->frame, NULL, GetModuleHandle(NULL), NULL);
2197             // CreateToolbarEx automatically sends this but CreateWindowEx doesn't.
2198             SendMessage(window->toolbar.toolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
2199
2200             GetClientRect(window->frame, &rect);
2201             MoveWindow( window->toolbar.toolbar, 0, 0,
2202                         rect.right - rect.left, default_height, TRUE);
2203             SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
2204             ShowWindow(window->toolbar.toolbar, SW_SHOW);
2205
2206             window->toolbar.first = 0;
2207             window->toolbar.pos = 0;
2208             window->toolbar.rows = 0;
2209             window->toolbar.toolBarProc =
2210                 (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);
2211
2212             icvUpdateWindowPos(window);
2213
2214             // Subclassing from toolbar
2215             icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
2216             icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
2217         }
2218
2219         /* Retrieve current buttons count */
2220         bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
2221
2222         if(bcount > 1)
2223         {
2224             /* If this is not the first button then we need to
2225             separate it from the previous one */
2226             tbs.iBitmap = 0;
2227             tbs.idCommand = bcount; // Set button id to it's number
2228             tbs.iString = 0;
2229             tbs.fsStyle = TBSTYLE_SEP;
2230             tbs.fsState = TBSTATE_ENABLED;
2231             SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
2232
2233             // Retrieve current buttons count
2234             bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
2235         }
2236
2237         /* Add a button which we're going to cover with the slider */
2238         tbs.iBitmap = 0;
2239         tbs.idCommand = bcount; // Set button id to it's number
2240         tbs.fsState = TBSTATE_ENABLED;
2241 #if 0/*!defined WIN64 && !defined EM64T*/
2242         tbs.fsStyle = 0;
2243         tbs.iString = 0;
2244 #else
2245
2246 #ifndef TBSTYLE_AUTOSIZE
2247 #define TBSTYLE_AUTOSIZE        0x0010
2248 #endif
2249
2250 #ifndef TBSTYLE_GROUP
2251 #define TBSTYLE_GROUP           0x0004
2252 #endif
2253         //tbs.fsStyle = TBSTYLE_AUTOSIZE;
2254         tbs.fsStyle = TBSTYLE_GROUP;
2255         tbs.iString = (INT_PTR)trackbar_text;
2256 #endif
2257         SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
2258
2259         /* Adjust button size to the slider */
2260         tbis.cbSize = sizeof(tbis);
2261         tbis.dwMask = TBIF_SIZE;
2262
2263         GetClientRect(window->hwnd, &rect);
2264         tbis.cx = (unsigned short)(rect.right - rect.left);
2265
2266         SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
2267             (WPARAM)tbs.idCommand, (LPARAM)&tbis);
2268
2269         /* Get button pos */
2270         SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
2271             (WPARAM)tbs.idCommand, (LPARAM)&rect);
2272
2273         /* Create a slider */
2274         trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
2275         trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
2276         trackbar->notify = 0;
2277         trackbar->notify2 = 0;
2278         trackbar->parent = window;
2279         trackbar->pos = 0;
2280         trackbar->data = 0;
2281         trackbar->id = bcount;
2282         trackbar->next = window->toolbar.first;
2283         trackbar->name = (char*)(trackbar + 1);
2284         memcpy( trackbar->name, trackbar_name, len + 1 );
2285         window->toolbar.first = trackbar;
2286
2287         sprintf(slider_name, "Trackbar%p", val);
2288         trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
2289                             WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
2290                             TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
2291                             rect.left + HG_BUDDY_WIDTH, rect.top,
2292                             rect.right - rect.left - HG_BUDDY_WIDTH,
2293                             rect.bottom - rect.top, window->toolbar.toolbar,
2294                             (HMENU)(size_t)bcount, hg_hinstance, 0);
2295
2296         sprintf(slider_name,"Buddy%p", val);
2297         trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
2298                             WS_CHILD | SS_RIGHT,
2299                             rect.left, rect.top,
2300                             HG_BUDDY_WIDTH, rect.bottom - rect.top,
2301                             window->toolbar.toolbar, 0, hg_hinstance, 0);
2302
2303         icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
2304
2305         /* Minimize the number of rows */
2306         SendMessage( window->toolbar.toolbar, TB_SETROWS,
2307                      MAKEWPARAM(1, FALSE), (LPARAM)&rect );
2308     }
2309     else
2310     {
2311         trackbar->data = 0;
2312         trackbar->notify = 0;
2313         trackbar->notify2 = 0;
2314     }
2315
2316     trackbar->maxval = count;
2317
2318     /* Adjust slider parameters */
2319     SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0);
2320     SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)count);
2321     SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
2322     if( val )
2323         pos = *val;
2324
2325     SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
2326     SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
2327
2328     trackbar->pos = -1;
2329     icvUpdateTrackbar( trackbar, pos );
2330     ShowWindow( trackbar->buddy, SW_SHOW );
2331     ShowWindow( trackbar->hwnd, SW_SHOW );
2332
2333     trackbar->notify = on_notify;
2334     trackbar->notify2 = on_notify2;
2335     trackbar->userdata = userdata;
2336     trackbar->data = val;
2337
2338     /* Resize the window to reflect the toolbar resizing*/
2339     icvUpdateWindowPos(window);
2340
2341     result = 1;
2342
2343     __END__;
2344
2345     return result;
2346 }
2347
2348 CV_IMPL int
2349 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
2350                   int* val, int count, CvTrackbarCallback on_notify )
2351 {
2352     return icvCreateTrackbar( trackbar_name, window_name, val, count,
2353         on_notify, 0, 0 );
2354 }
2355
2356 CV_IMPL int
2357 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
2358                    int* val, int count, CvTrackbarCallback2 on_notify2,
2359                    void* userdata )
2360 {
2361     return icvCreateTrackbar( trackbar_name, window_name, val, count,
2362         0, on_notify2, userdata );
2363 }
2364
2365 CV_IMPL void
2366 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
2367 {
2368     CV_FUNCNAME( "cvSetMouseCallback" );
2369
2370     __BEGIN__;
2371
2372     CvWindow* window = 0;
2373
2374     if( !window_name )
2375         CV_ERROR( CV_StsNullPtr, "NULL window name" );
2376
2377     window = icvFindWindowByName(window_name);
2378     if( !window )
2379         EXIT;
2380
2381     window->on_mouse = on_mouse;
2382     window->on_mouse_param = param;
2383
2384     __END__;
2385 }
2386
2387
2388 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
2389 {
2390     int pos = -1;
2391
2392     CV_FUNCNAME( "cvGetTrackbarPos" );
2393
2394     __BEGIN__;
2395
2396     CvWindow* window;
2397     CvTrackbar* trackbar = 0;
2398
2399     if( trackbar_name == 0 || window_name == 0 )
2400         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
2401
2402     window = icvFindWindowByName( window_name );
2403     if( window )
2404         trackbar = icvFindTrackbarByName( window, trackbar_name );
2405
2406     if( trackbar )
2407         pos = trackbar->pos;
2408
2409     __END__;
2410
2411     return pos;
2412 }
2413
2414
2415 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
2416 {
2417     CV_FUNCNAME( "cvSetTrackbarPos" );
2418
2419     __BEGIN__;
2420
2421     CvWindow* window;
2422     CvTrackbar* trackbar = 0;
2423
2424     if( trackbar_name == 0 || window_name == 0 )
2425         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
2426
2427     window = icvFindWindowByName( window_name );
2428     if( window )
2429         trackbar = icvFindTrackbarByName( window, trackbar_name );
2430
2431     if( trackbar )
2432     {
2433         if( pos < 0 )
2434             pos = 0;
2435
2436         if( pos > trackbar->maxval )
2437             pos = trackbar->maxval;
2438
2439         SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
2440         icvUpdateTrackbar( trackbar, pos );
2441     }
2442
2443     __END__;
2444 }
2445
2446
2447 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
2448 {
2449     CV_FUNCNAME( "cvSetTrackbarMax" );
2450
2451     __BEGIN__;
2452
2453     if (maxval >= 0)
2454     {
2455         CvWindow* window = 0;
2456         CvTrackbar* trackbar = 0;
2457         if (trackbar_name == 0 || window_name == 0)
2458         {
2459             CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
2460         }
2461
2462         window = icvFindWindowByName(window_name);
2463         if (window)
2464         {
2465             trackbar = icvFindTrackbarByName(window, trackbar_name);
2466             if (trackbar)
2467             {
2468                 // The position will be min(pos, maxval).
2469                 trackbar->maxval = (trackbar->minval>maxval)?trackbar->minval:maxval;
2470                 SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
2471             }
2472         }
2473     }
2474
2475     __END__;
2476 }
2477
2478
2479 CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)
2480 {
2481     CV_FUNCNAME( "cvSetTrackbarMin" );
2482
2483     __BEGIN__;
2484
2485     if (minval >= 0)
2486     {
2487         CvWindow* window = 0;
2488         CvTrackbar* trackbar = 0;
2489         if (trackbar_name == 0 || window_name == 0)
2490         {
2491             CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
2492         }
2493
2494         window = icvFindWindowByName(window_name);
2495         if (window)
2496         {
2497             trackbar = icvFindTrackbarByName(window, trackbar_name);
2498             if (trackbar)
2499             {
2500                 // The position will be min(pos, maxval).
2501                 trackbar->minval = (minval<trackbar->maxval)?minval:trackbar->maxval;
2502                 SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)minval);
2503             }
2504         }
2505     }
2506
2507     __END__;
2508 }
2509
2510
2511 CV_IMPL void* cvGetWindowHandle( const char* window_name )
2512 {
2513     void* hwnd = 0;
2514
2515     CV_FUNCNAME( "cvGetWindowHandle" );
2516
2517     __BEGIN__;
2518
2519     CvWindow* window;
2520
2521     if( window_name == 0 )
2522         CV_ERROR( CV_StsNullPtr, "NULL window name" );
2523
2524     window = icvFindWindowByName( window_name );
2525     if( window )
2526         hwnd = (void*)window->hwnd;
2527
2528     __END__;
2529
2530     return hwnd;
2531 }
2532
2533
2534 CV_IMPL const char* cvGetWindowName( void* window_handle )
2535 {
2536     const char* window_name = "";
2537
2538     CV_FUNCNAME( "cvGetWindowName" );
2539
2540     __BEGIN__;
2541
2542     CvWindow* window;
2543
2544     if( window_handle == 0 )
2545         CV_ERROR( CV_StsNullPtr, "NULL window" );
2546
2547     window = icvWindowByHWND( (HWND)window_handle );
2548     if( window )
2549         window_name = window->name;
2550
2551     __END__;
2552
2553     return window_name;
2554 }
2555
2556
2557 CV_IMPL void
2558 cvSetPreprocessFuncWin32_(const void* callback)
2559 {
2560     hg_on_preprocess = (CvWin32WindowCallback)callback;
2561 }
2562
2563 CV_IMPL void
2564 cvSetPostprocessFuncWin32_(const void* callback)
2565 {
2566     hg_on_postprocess = (CvWin32WindowCallback)callback;
2567 }
2568
2569 #endif //_WIN32