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