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