1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
42 #include "precomp.hpp"
46 #include <windowsx.h> // required for GET_X_LPARAM() and GET_Y_LPARAM() macros
51 # pragma GCC diagnostic ignored "-Wmissing-declarations"
54 #if (_WIN32_IE < 0x0500)
55 #pragma message("WARNING: Win32 UI needs to be compiled with _WIN32_IE >= 0x0500 (_WIN32_IE_IE50)")
56 #define _WIN32_IE 0x0500
70 #include "opencv2/highgui.hpp"
72 #include "opencv2/core/opengl.hpp"
75 static const char* trackbar_text =
78 #if defined _M_X64 || defined __x86_64
80 #define icvGetWindowLongPtr GetWindowLongPtr
81 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
82 #define icvGetClassLongPtr GetClassLongPtr
84 #define CV_USERDATA GWLP_USERDATA
85 #define CV_WNDPROC GWLP_WNDPROC
86 #define CV_HCURSOR GCLP_HCURSOR
87 #define CV_HBRBACKGROUND GCLP_HBRBACKGROUND
91 #define icvGetWindowLongPtr GetWindowLong
92 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
93 #define icvGetClassLongPtr GetClassLong
95 #define CV_USERDATA GWL_USERDATA
96 #define CV_WNDPROC GWL_WNDPROC
97 #define CV_HCURSOR GCL_HCURSOR
98 #define CV_HBRBACKGROUND GCL_HBRBACKGROUND
102 #ifndef WM_MOUSEHWHEEL
103 #define WM_MOUSEHWHEEL 0x020E
106 static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
108 assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
110 BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
112 memset( bmih, 0, sizeof(*bmih));
113 bmih->biSize = sizeof(BITMAPINFOHEADER);
114 bmih->biWidth = width;
115 bmih->biHeight = origin ? abs(height) : -abs(height);
117 bmih->biBitCount = (unsigned short)bpp;
118 bmih->biCompression = BI_RGB;
122 RGBQUAD* palette = bmi->bmiColors;
124 for( i = 0; i < 256; i++ )
126 palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
127 palette[i].rgbReserved = 0;
134 typedef struct CvTrackbar
147 void (*notify2)(int, void*);
154 typedef struct CvWindow
167 int status;//0 normal, 1 fullscreen (YV)
169 CvMouseCallback on_mouse;
170 void* on_mouse_param;
191 CvOpenGlDrawCallback glDrawCallback;
197 #define HG_BUDDY_WIDTH 130
200 #define TBIF_SIZE 0x40
203 #ifndef TB_SETBUTTONINFO
204 #define TB_SETBUTTONINFO (WM_USER + 66)
207 #ifndef TBM_GETTOOLTIPS
208 #define TBM_GETTOOLTIPS (WM_USER + 30)
211 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
212 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
213 static LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
214 static void icvUpdateWindowPos( CvWindow* window );
216 static CvWindow* hg_windows = 0;
218 typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*);
219 static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
220 static HINSTANCE hg_hinstance = 0;
222 static const char* highGUIclassName = "HighGUI class";
223 static const char* mainHighGUIclassName = "Main HighGUI class";
225 static void icvCleanupHighgui()
227 cvDestroyAllWindows();
228 UnregisterClass(highGUIclassName, hg_hinstance);
229 UnregisterClass(mainHighGUIclassName, hg_hinstance);
232 CV_IMPL int cvInitSystem( int, char** )
234 static int wasInitialized = 0;
236 // check initialization status
237 if( !wasInitialized )
239 // Initialize the stogare
242 // Register the class
244 wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
245 wndc.lpfnWndProc = WindowProc;
248 wndc.hInstance = hg_hinstance;
249 wndc.lpszClassName = highGUIclassName;
250 wndc.lpszMenuName = highGUIclassName;
251 wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
252 wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
253 wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
255 RegisterClass(&wndc);
257 wndc.lpszClassName = mainHighGUIclassName;
258 wndc.lpszMenuName = mainHighGUIclassName;
259 wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
260 wndc.lpfnWndProc = MainWindowProc;
262 RegisterClass(&wndc);
263 atexit( icvCleanupHighgui );
268 setlocale(LC_NUMERIC,"C");
273 CV_IMPL int cvStartWindowThread(){
277 static CvWindow* icvFindWindowByName( const char* name )
279 CvWindow* window = hg_windows;
281 for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
288 static CvWindow* icvWindowByHWND( HWND hwnd )
290 CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
291 return window != 0 && hg_windows != 0 &&
292 window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
296 static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
298 CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
299 return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
300 trackbar->hwnd == hwnd ? trackbar : 0;
304 static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
306 // Window positions saving/loading added by Philip Gruebele.
307 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
308 // Restores the window position from the registry saved position.
310 icvLoadWindowPos( const char* name, CvRect& rect )
314 strcpy_s( szKey, 1024, icvWindowPosRootKey );
315 strcat_s( szKey, 1024, name );
317 rect.x = rect.y = CW_USEDEFAULT;
318 rect.width = rect.height = 320;
320 if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
322 // Yes we are installed.
324 DWORD dwSize = sizeof(int);
326 RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize);
327 RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize);
328 RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize);
329 RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize);
331 // Snap rect into closest monitor in case it falls outside it. // Adi Shavit
332 // set WIN32 RECT to be the loaded size
333 POINT tl_w32 = { rect.x, rect.y };
334 POINT tr_w32 = { rect.x + rect.width, rect.y };
336 // find monitor containing top-left and top-right corners, or NULL
337 HMONITOR hMonitor_l = MonitorFromPoint(tl_w32, MONITOR_DEFAULTTONULL);
338 HMONITOR hMonitor_r = MonitorFromPoint(tr_w32, MONITOR_DEFAULTTONULL);
340 // if neither are contained - the move window to origin of closest.
341 if (NULL == hMonitor_l && NULL == hMonitor_r)
343 // find monitor nearest to top-left corner
344 HMONITOR hMonitor_closest = MonitorFromPoint(tl_w32, MONITOR_DEFAULTTONEAREST);
346 // get coordinates of nearest monitor
348 mi.cbSize = sizeof(mi);
349 GetMonitorInfo(hMonitor_closest, &mi);
351 rect.x = mi.rcWork.left;
352 rect.y = mi.rcWork.top;
355 if (rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000))
357 if (rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000))
365 // Window positions saving/loading added by Philip Gruebele.
366 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
367 // philipg. Saves the window position in the registry
369 icvSaveWindowPos( const char* name, CvRect rect )
371 static const DWORD MAX_RECORD_COUNT = 100;
375 strcpy_s( szKey, 1024, icvWindowPosRootKey );
376 strcat_s( szKey, 1024, name );
378 if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
382 FILETIME oldestTime = { UINT_MAX, UINT_MAX };
383 char oldestKey[1024];
384 char currentKey[1024];
386 strcpy_s( rootKey, 1024, icvWindowPosRootKey );
387 rootKey[strlen(rootKey)-1] = '\0';
388 if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
389 //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
394 DWORD csize = sizeof(currentKey);
395 FILETIME accesstime = { 0, 0 };
396 LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
397 if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
400 if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
401 (oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
402 oldestTime.dwLowDateTime > accesstime.dwLowDateTime) )
404 oldestTime = accesstime;
405 strcpy_s( oldestKey, 1024, currentKey );
409 if( count >= MAX_RECORD_COUNT )
410 RegDeleteKey( hroot, oldestKey );
411 RegCloseKey( hroot );
413 if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
419 if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
423 RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x));
424 RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y));
425 RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width));
426 RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height));
430 CvRect cvGetWindowRect_W32(const char* name)
432 CvRect result = cvRect(-1, -1, -1, -1);
434 CV_FUNCNAME( "cvGetWindowRect_W32" );
441 CV_ERROR( CV_StsNullPtr, "NULL name string" );
442 window = icvFindWindowByName( name );
444 EXIT; // keep silence here
447 GetClientRect(window->hwnd, &rect);
449 POINT pt = {rect.left, rect.top};
450 ClientToScreen(window->hwnd, &pt);
451 result = cvRect(pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top);
457 double cvGetModeWindow_W32(const char* name)//YV
461 CV_FUNCNAME( "cvGetModeWindow_W32" );
468 CV_ERROR( CV_StsNullPtr, "NULL name string" );
470 window = icvFindWindowByName( name );
472 EXIT; // keep silence here
474 result = window->status;
480 void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
482 CV_FUNCNAME( "cvSetModeWindow_W32" );
489 CV_ERROR( CV_StsNullPtr, "NULL name string" );
491 window = icvFindWindowByName( name );
493 CV_ERROR( CV_StsNullPtr, "NULL window" );
495 if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
499 DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE);
502 if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
504 icvLoadWindowPos(window->name,position );
505 SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);
507 SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
508 window->status=CV_WINDOW_NORMAL;
513 if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
517 GetWindowRect(window->frame, &rect);
518 CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top);
519 icvSaveWindowPos(window->name,RectCV );
521 //Look at coordinate for fullscreen
524 hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
526 mi.cbSize = sizeof(mi);
527 GetMonitorInfo(hMonitor, &mi);
530 position.x=mi.rcMonitor.left;position.y=mi.rcMonitor.top;
531 position.width=mi.rcMonitor.right - mi.rcMonitor.left;position.height=mi.rcMonitor.bottom - mi.rcMonitor.top;
532 SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME);
534 SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
535 window->status=CV_WINDOW_FULLSCREEN;
544 double cvGetPropTopmost_W32(const char* name)
550 CvWindow* window = icvFindWindowByName(name);
552 CV_Error(Error::StsNullPtr, "NULL window");
554 LONG style = GetWindowLongA(window->frame, GWL_EXSTYLE); // -20
557 std::ostringstream errorMsg;
558 errorMsg << "window(" << name << "): failed to retrieve extended window style using GetWindowLongA(); error code: " << GetLastError();
559 CV_Error(Error::StsError, errorMsg.str().c_str());
562 result = (style & WS_EX_TOPMOST) == WS_EX_TOPMOST;
567 void cvSetPropTopmost_W32(const char* name, const bool topmost)
571 CvWindow* window = icvFindWindowByName(name);
573 CV_Error(Error::StsNullPtr, "NULL window");
575 HWND flag = topmost ? HWND_TOPMOST : HWND_TOP;
576 BOOL success = SetWindowPos(window->frame, flag, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
580 std::ostringstream errorMsg;
581 errorMsg << "window(" << name << "): error reported by SetWindowPos(" << (topmost ? "HWND_TOPMOST" : "HWND_TOP") << "), error code: " << GetLastError();
582 CV_Error(Error::StsError, errorMsg.str().c_str());
586 void cv::setWindowTitle(const String& winname, const String& title)
588 CvWindow* window = icvFindWindowByName(winname.c_str());
592 namedWindow(winname);
593 window = icvFindWindowByName(winname.c_str());
597 CV_Error(Error::StsNullPtr, "NULL window");
599 if (!SetWindowText(window->frame, title.c_str()))
600 CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", winname.c_str(), title.c_str()));
603 double cvGetPropWindowAutoSize_W32(const char* name)
607 CV_FUNCNAME( "cvSetCloseCallback" );
614 CV_ERROR( CV_StsNullPtr, "NULL name string" );
616 window = icvFindWindowByName( name );
618 EXIT; // keep silence here
620 result = window->flags & CV_WINDOW_AUTOSIZE;
627 double cvGetRatioWindow_W32(const char* name)
631 CV_FUNCNAME( "cvGetRatioWindow_W32" );
638 CV_ERROR( CV_StsNullPtr, "NULL name string" );
640 window = icvFindWindowByName( name );
642 EXIT; // keep silence here
644 result = static_cast<double>(window->width) / window->height;
651 double cvGetOpenGlProp_W32(const char* name)
656 CV_FUNCNAME( "cvGetOpenGlProp_W32" );
663 CV_ERROR( CV_StsNullPtr, "NULL name string" );
665 window = icvFindWindowByName( name );
667 EXIT; // keep silence here
669 result = window->useGl;
678 double cvGetPropVisible_W32(const char* name)
682 CV_FUNCNAME( "cvGetPropVisible_W32" );
687 CV_ERROR( CV_StsNullPtr, "NULL name string" );
689 result = (icvFindWindowByName( name ) != NULL);
703 void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl)
705 CV_FUNCNAME( "createGlContext" );
713 static PIXELFORMATDESCRIPTOR pfd =
715 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
717 PFD_DRAW_TO_WINDOW | // Format Must Support Window
718 PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
719 PFD_DOUBLEBUFFER, // Must Support Double Buffering
720 PFD_TYPE_RGBA, // Request An RGBA Format
721 32, // Select Our Color Depth
722 0, 0, 0, 0, 0, 0, // Color Bits Ignored
723 0, // No Alpha Buffer
724 0, // Shift Bit Ignored
725 0, // No Accumulation Buffer
726 0, 0, 0, 0, // Accumulation Bits Ignored
727 32, // 32 Bit Z-Buffer (Depth Buffer)
728 0, // No Stencil Buffer
729 0, // No Auxiliary Buffer
730 PFD_MAIN_PLANE, // Main Drawing Layer
732 0, 0, 0 // Layer Masks Ignored
737 CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
739 PixelFormat = ChoosePixelFormat(hGLDC, &pfd);
741 CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" );
743 if (!SetPixelFormat(hGLDC, PixelFormat, &pfd))
744 CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" );
746 hGLRC = wglCreateContext(hGLDC);
748 CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" );
750 if (!wglMakeCurrent(hGLDC, hGLRC))
751 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
758 void releaseGlContext(CvWindow* window)
760 //CV_FUNCNAME( "releaseGlContext" );
766 wglDeleteContext(window->hGLRC);
767 window->hGLRC = NULL;
772 ReleaseDC(window->hwnd, window->dc);
776 window->useGl = false;
781 void drawGl(CvWindow* window)
783 CV_FUNCNAME( "drawGl" );
787 if (!wglMakeCurrent(window->dc, window->hGLRC))
788 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
790 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
792 if (window->glDrawCallback)
793 window->glDrawCallback(window->glDrawData);
795 if (!SwapBuffers(window->dc))
796 CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" );
801 void resizeGl(CvWindow* window)
803 CV_FUNCNAME( "resizeGl" );
807 if (!wglMakeCurrent(window->dc, window->hGLRC))
808 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
810 glViewport(0, 0, window->width, window->height);
816 #endif // HAVE_OPENGL
819 CV_IMPL int cvNamedWindow( const char* name, int flags )
822 CV_FUNCNAME( "cvNamedWindow" );
828 DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
840 CV_ERROR( CV_StsNullPtr, "NULL name string" );
842 // Check the name in the storage
843 window = icvFindWindowByName( name );
850 if( !(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
851 defStyle |= WS_SIZEBOX;
854 if (flags & CV_WINDOW_OPENGL)
855 defStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
858 icvLoadWindowPos( name, rect );
860 mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
861 rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
863 CV_ERROR( CV_StsError, "Frame window can not be created" );
865 ShowWindow(mainhWnd, SW_SHOW);
867 //YV- remove one border by changing the style
868 hWnd = CreateWindow("HighGUI class", "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
870 CV_ERROR( CV_StsError, "Frame window can not be created" );
873 if (flags & CV_WINDOW_OPENGL)
874 CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
880 if (flags & CV_WINDOW_OPENGL)
881 createGlContext(hWnd, hGLDC, hGLRC, useGl);
884 ShowWindow(hWnd, SW_SHOW);
886 len = (int)strlen(name);
887 CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
889 window->signature = CV_WINDOW_MAGIC_VAL;
891 window->frame = mainhWnd;
892 window->name = (char*)(window + 1);
893 memcpy( window->name, name, len + 1 );
894 window->flags = flags;
898 window->dc = CreateCompatibleDC(0);
902 window->dc = CreateCompatibleDC(0);
904 window->useGl = false;
909 window->hGLRC = hGLRC;
910 window->useGl = true;
913 window->glDrawCallback = 0;
914 window->glDrawData = 0;
917 window->last_key = 0;
918 window->status = CV_WINDOW_NORMAL;//YV
920 window->on_mouse = 0;
921 window->on_mouse_param = 0;
923 memset( &window->toolbar, 0, sizeof(window->toolbar));
925 window->next = hg_windows;
928 hg_windows->prev = window;
930 icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
931 icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
933 // Recalculate window pos
934 icvUpdateWindowPos( window );
944 CV_IMPL void cvSetOpenGlContext(const char* name)
946 CV_FUNCNAME( "cvSetOpenGlContext" );
953 CV_ERROR( CV_StsNullPtr, "NULL name string" );
955 window = icvFindWindowByName( name );
957 CV_ERROR( CV_StsNullPtr, "NULL window" );
960 CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
962 if (!wglMakeCurrent(window->dc, window->hGLRC))
963 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
968 CV_IMPL void cvUpdateWindow(const char* name)
970 CV_FUNCNAME( "cvUpdateWindow" );
977 CV_ERROR( CV_StsNullPtr, "NULL name string" );
979 window = icvFindWindowByName( name );
983 InvalidateRect(window->hwnd, 0, 0);
988 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
990 CV_FUNCNAME( "cvCreateOpenGLCallback" );
997 CV_ERROR( CV_StsNullPtr, "NULL name string" );
999 window = icvFindWindowByName( name );
1004 CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
1006 window->glDrawCallback = callback;
1007 window->glDrawData = userdata;
1012 #endif // HAVE_OPENGL
1014 static void icvRemoveWindow( CvWindow* window )
1016 CvTrackbar* trackbar = NULL;
1017 RECT wrect={0,0,0,0};
1021 releaseGlContext(window);
1025 GetWindowRect( window->frame, &wrect );
1027 icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
1028 wrect.right-wrect.left, wrect.bottom-wrect.top) );
1031 icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
1033 icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
1035 if( window->toolbar.toolbar )
1036 icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0);
1039 window->prev->next = window->next;
1041 hg_windows = window->next;
1044 window->next->prev = window->prev;
1046 window->prev = window->next = 0;
1048 if( window->dc && window->image )
1049 DeleteObject(SelectObject(window->dc,window->image));
1052 DeleteDC(window->dc);
1054 for( trackbar = window->toolbar.first; trackbar != 0; )
1056 CvTrackbar* next = trackbar->next;
1057 if( trackbar->hwnd )
1059 icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
1060 cvFree( &trackbar );
1069 CV_IMPL void cvDestroyWindow( const char* name )
1071 CV_FUNCNAME( "cvDestroyWindow" );
1079 CV_ERROR( CV_StsNullPtr, "NULL name string" );
1081 window = icvFindWindowByName( name );
1085 mainhWnd = window->frame;
1087 SendMessage(window->hwnd, WM_CLOSE, 0, 0);
1088 SendMessage( mainhWnd, WM_CLOSE, 0, 0);
1089 // Do NOT call _remove_window -- CvWindow list will be updated automatically ...
1095 static void icvScreenToClient( HWND hwnd, RECT* rect )
1100 ScreenToClient(hwnd, &p);
1101 OffsetRect( rect, p.x - rect->left, p.y - rect->top );
1105 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
1106 static RECT icvCalcWindowRect( CvWindow* window )
1108 const int gutter = 1;
1109 RECT crect, trect, rect;
1113 GetClientRect(window->frame, &crect);
1114 if(window->toolbar.toolbar)
1116 GetWindowRect(window->toolbar.toolbar, &trect);
1117 icvScreenToClient(window->frame, &trect);
1118 SubtractRect( &rect, &crect, &trect);
1124 rect.left += gutter;
1125 rect.bottom -= gutter;
1126 rect.right -= gutter;
1131 // returns TRUE if there is a problem such as ERROR_IO_PENDING.
1132 static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
1136 HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
1138 size->cx = size->cy = 0;
1144 if (GetObject(h, sizeof(bmp), &bmp) == 0)
1149 size->cx = abs(bmp.bmWidth);
1150 size->cy = abs(bmp.bmHeight);
1154 *channels = bmp.bmBitsPixel/8;
1163 static void icvUpdateWindowPos( CvWindow* window )
1168 if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
1172 icvGetBitmapData( window, &size, 0, 0 );
1174 // Repeat two times because after the first resizing of the mainhWnd window
1175 // toolbar may resize too
1176 for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
1178 RECT rmw, rw = icvCalcWindowRect(window );
1179 MoveWindow(window->hwnd, rw.left, rw.top,
1180 rw.right - rw.left, rw.bottom - rw.top, FALSE);
1181 GetClientRect(window->hwnd, &rw);
1182 GetWindowRect(window->frame, &rmw);
1183 // Resize the mainhWnd window in order to make the bitmap fit into the child window
1184 MoveWindow(window->frame, rmw.left, rmw.top,
1185 size.cx + (rmw.right - rmw.left) - (rw.right - rw.left),
1186 size.cy + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE );
1190 rect = icvCalcWindowRect(window);
1191 MoveWindow(window->hwnd, rect.left, rect.top,
1192 rect.right - rect.left,
1193 rect.bottom - rect.top, TRUE );
1197 cvShowImage( const char* name, const CvArr* arr )
1199 CV_FUNCNAME( "cvShowImage" );
1204 SIZE size = { 0, 0 };
1207 const int channels0 = 3;
1209 CvMat stub, dst, *image;
1210 bool changed_size = false; // philipg
1213 CV_ERROR( CV_StsNullPtr, "NULL name" );
1215 window = icvFindWindowByName(name);
1218 cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
1219 window = icvFindWindowByName(name);
1222 if( !window || !arr )
1223 EXIT; // keep silence here.
1225 if( CV_IS_IMAGE_HDR( arr ))
1226 origin = ((IplImage*)arr)->origin;
1228 CV_CALL( image = cvGetMat( arr, &stub ));
1233 cv::imshow(name, cv::cvarrToMat(image));
1239 // if there is something wrong with these system calls, we cannot display image...
1240 if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
1243 if( size.cx != image->width || size.cy != image->height || channels != channels0 )
1245 changed_size = true;
1247 uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
1248 BITMAPINFO* binfo = (BITMAPINFO*)buffer;
1250 DeleteObject( SelectObject( window->dc, window->image ));
1253 size.cx = image->width;
1254 size.cy = image->height;
1255 channels = channels0;
1257 FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
1259 window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
1260 DIB_RGB_COLORS, &dst_ptr, 0, 0));
1263 cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3,
1264 dst_ptr, (size.cx * channels + 3) & -4 );
1265 cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
1267 // only resize window if needed
1269 icvUpdateWindowPos(window);
1270 InvalidateRect(window->hwnd, 0, 0);
1271 // philipg: this is not needed and just slows things down
1272 // UpdateWindow(window->hwnd);
1279 cvShowImageHWND(HWND w_hWnd, const CvArr* arr)
1281 CV_FUNCNAME( "cvShowImageHWND" );
1285 SIZE size = { 0, 0 };
1288 const int channels0 = 3;
1290 CvMat stub, dst, *image;
1291 bool changed_size = false;
1292 BITMAPINFO tempbinfo;
1300 hdc = GetDC(w_hWnd);
1302 if( CV_IS_IMAGE_HDR( arr ) )
1303 origin = ((IplImage*)arr)->origin;
1305 CV_CALL( image = cvGetMat( arr, &stub ) );
1312 HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );
1316 if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
1319 channels = bmp.bmBitsPixel/8;
1320 dst_ptr = bmp.bmBits;
1323 if( size.cx != image->width || size.cy != image->height || channels != channels0 )
1325 changed_size = true;
1327 uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
1328 BITMAPINFO* binfo = (BITMAPINFO*)buffer;
1330 BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
1331 CV_Assert( FALSE != bDeleteObj );
1333 size.cx = image->width;
1334 size.cy = image->height;
1335 channels = channels0;
1337 FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
1339 SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
1342 cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 );
1343 cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
1345 // Image stretching to fit the window
1347 GetClientRect(w_hWnd, &rect);
1348 StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, &tempbinfo, DIB_RGB_COLORS, SRCCOPY );
1350 // ony resize window if needed
1351 InvalidateRect(w_hWnd, 0, 0);
1357 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1359 CV_FUNCNAME( "cvResizeWindow" );
1368 CV_ERROR( CV_StsNullPtr, "NULL name" );
1370 window = icvFindWindowByName(name);
1374 // Repeat two times because after the first resizing of the mainhWnd window
1375 // toolbar may resize too
1376 for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
1378 rw = icvCalcWindowRect(window);
1379 MoveWindow(window->hwnd, rw.left, rw.top,
1380 rw.right - rw.left, rw.bottom - rw.top, FALSE);
1381 GetClientRect(window->hwnd, &rw);
1382 GetWindowRect(window->frame, &rmw);
1383 // Resize the mainhWnd window in order to make the bitmap fit into the child window
1384 MoveWindow(window->frame, rmw.left, rmw.top,
1385 width + (rmw.right - rmw.left) - (rw.right - rw.left),
1386 height + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE);
1389 rect = icvCalcWindowRect(window);
1390 MoveWindow(window->hwnd, rect.left, rect.top,
1391 rect.right - rect.left, rect.bottom - rect.top, TRUE);
1397 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1399 CV_FUNCNAME( "cvMoveWindow" );
1407 CV_ERROR( CV_StsNullPtr, "NULL name" );
1409 window = icvFindWindowByName(name);
1413 GetWindowRect( window->frame, &rect );
1414 MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
1420 static LRESULT CALLBACK
1421 MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1423 CvWindow* window = icvWindowByHWND( hwnd );
1425 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1430 ::SendMessage(window->hwnd, uMsg, wParam, lParam);
1435 icvRemoveWindow(window);
1437 //PostQuitMessage(0);
1440 case WM_GETMINMAXINFO:
1441 if( !(window->flags & CV_WINDOW_AUTOSIZE) )
1443 MINMAXINFO* minmax = (MINMAXINFO*)lParam;
1445 LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);
1447 minmax->ptMinTrackSize.y = 100;
1448 minmax->ptMinTrackSize.x = 100;
1450 if( window->toolbar.first )
1452 GetWindowRect( window->toolbar.first->hwnd, &rect );
1453 minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
1454 minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
1460 case WM_WINDOWPOSCHANGED:
1462 WINDOWPOS* pos = (WINDOWPOS*)lParam;
1464 // Update the toolbar pos/size
1465 if(window->toolbar.toolbar)
1468 GetWindowRect(window->toolbar.toolbar, &rect);
1469 MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
1472 if(!(window->flags & CV_WINDOW_AUTOSIZE))
1473 icvUpdateWindowPos(window);
1478 case WM_WINDOWPOSCHANGING:
1480 // Snap window to screen edges with multi-monitor support. // Adi Shavit
1481 LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
1484 GetWindowRect(window->frame, &rect);
1487 hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
1490 mi.cbSize = sizeof(mi);
1491 GetMonitorInfo(hMonitor, &mi);
1493 const int SNAP_DISTANCE = 15;
1495 if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
1496 pos->x = mi.rcMonitor.left; // snap to left edge
1498 if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
1499 pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge
1501 if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
1502 pos->y = mi.rcMonitor.top; // snap to top edge
1504 if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
1505 pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
1509 if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
1510 SetFocus(window->hwnd);
1514 case WM_MOUSEHWHEEL:
1515 if( window->on_mouse )
1517 int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
1518 (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
1519 (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
1520 (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
1521 (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
1522 (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
1523 int event = (uMsg == WM_MOUSEWHEEL ? CV_EVENT_MOUSEWHEEL : CV_EVENT_MOUSEHWHEEL);
1525 // Set the wheel delta of mouse wheel to be in the upper word of 'event'
1526 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
1527 flags |= (delta << 16);
1530 pt.x = GET_X_LPARAM( lParam );
1531 pt.y = GET_Y_LPARAM( lParam );
1532 ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates.
1535 GetClientRect( window->hwnd, &rect );
1541 cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window->glDrawData);
1542 size.cx = texObj->cols();
1543 size.cy = texObj->rows();
1547 icvGetBitmapData(window, &size, 0, 0);
1550 icvGetBitmapData(window, &size, 0, 0);
1553 window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
1554 pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
1555 window->on_mouse_param );
1562 HRGN rgn, rgn1, rgn2;
1564 HDC hdc = (HDC)wParam;
1565 GetWindowRect(window->hwnd, &cr);
1566 icvScreenToClient(window->frame, &cr);
1567 if(window->toolbar.toolbar)
1569 GetWindowRect(window->toolbar.toolbar, &tr);
1570 icvScreenToClient(window->frame, &tr);
1573 tr.left = tr.top = tr.right = tr.bottom = 0;
1575 GetClientRect(window->frame, &wrc);
1577 rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
1578 rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
1579 rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom);
1580 CV_Assert_N(rgn != 0, rgn1 != 0, rgn2 != 0);
1582 ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
1583 ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
1585 if(ret != NULLREGION && ret != ERROR)
1586 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
1595 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1599 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1601 CvWindow* window = icvWindowByHWND(hwnd);
1603 // This window is not mentioned in HighGUI storage
1604 // Actually, this should be error except for the case of calls to CreateWindow
1605 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1607 // Process the message
1612 if (!::OpenClipboard(hwnd) )
1619 // We'll use a do-while(0){} scope as a single-run breakable scope
1620 // Upon any error we can jump out of the single-time while scope to clean up the resources.
1623 if (!::EmptyClipboard())
1629 // Get window device context
1630 if (0 == (hDC = ::GetDC(hwnd)))
1633 // Create another DC compatible with hDC
1634 if (0 == (memDC = ::CreateCompatibleDC( hDC )))
1637 // Determine the bitmap's dimensions
1640 icvGetBitmapData( window, &size, &nchannels, 0 );
1642 // Create bitmap to draw on and it in the new DC
1643 if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy)))
1646 if (!::SelectObject( memDC, memBM ))
1649 // Begin drawing to DC
1650 if (!::SetStretchBltMode(memDC, COLORONCOLOR))
1654 if( 1 == nchannels )
1656 for(int i = 0; i < 256; ++i)
1658 table[i].rgbBlue = (unsigned char)i;
1659 table[i].rgbGreen = (unsigned char)i;
1660 table[i].rgbRed = (unsigned char)i;
1662 if (!::SetDIBColorTable(window->dc, 0, 255, table))
1666 // The image copied to the clipboard will be in its original size, regardless if the window itself was resized.
1668 // Render the image to the dc/bitmap (at original size).
1669 if (!::BitBlt( memDC, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY ))
1672 // Finally, set bitmap to clipboard
1673 ::SetClipboardData(CF_BITMAP, memBM);
1674 } while (0,0); // (0,0) instead of (0) to avoid MSVC compiler warning C4127: "conditional expression is constant"
1676 //////////////////////////////////////////////////////////////////////////
1677 // if handle is allocated (i.e. != 0) then clean-up.
1678 if (memBM) ::DeleteObject(memBM);
1679 if (memDC) ::DeleteDC(memDC);
1680 if (hDC) ::ReleaseDC(hwnd, hDC);
1685 case WM_WINDOWPOSCHANGING:
1687 LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
1688 RECT rect = icvCalcWindowRect(window);
1691 pos->cx = rect.right - rect.left;
1692 pos->cy = rect.bottom - rect.top;
1696 case WM_LBUTTONDOWN:
1697 case WM_RBUTTONDOWN:
1698 case WM_MBUTTONDOWN:
1699 case WM_LBUTTONDBLCLK:
1700 case WM_RBUTTONDBLCLK:
1701 case WM_MBUTTONDBLCLK:
1706 if( window->on_mouse )
1710 int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
1711 (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
1712 (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
1713 (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
1714 (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
1715 (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
1716 int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN :
1717 uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN :
1718 uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN :
1719 uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP :
1720 uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP :
1721 uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP :
1722 uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK :
1723 uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
1724 uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
1726 if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
1728 if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
1731 pt.x = GET_X_LPARAM( lParam );
1732 pt.y = GET_Y_LPARAM( lParam );
1734 if (window->flags & CV_WINDOW_AUTOSIZE)
1736 // As user can't change window size, do not scale window coordinates. Underlying windowing system
1737 // may prevent full window from being displayed and in this case coordinates should not be scaled.
1738 window->on_mouse( event, pt.x, pt.y, flags, window->on_mouse_param );
1740 // Full window is displayed using different size. Scale coordinates to match underlying positions.
1744 GetClientRect( window->hwnd, &rect );
1749 cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window->glDrawData);
1750 size.cx = texObj->cols();
1751 size.cy = texObj->rows();
1755 icvGetBitmapData(window, &size, 0, 0);
1758 icvGetBitmapData( window, &size, 0, 0 );
1761 window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
1762 pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
1763 window->on_mouse_param );
1769 if(window->image != 0)
1777 // Determine the bitmap's dimensions
1778 icvGetBitmapData( window, &size, &nchannels, 0 );
1780 hdc = BeginPaint(hwnd, &paint);
1781 SetStretchBltMode(hdc, COLORONCOLOR);
1783 if( nchannels == 1 )
1786 for(i = 0; i < 256; i++)
1788 table[i].rgbBlue = (unsigned char)i;
1789 table[i].rgbGreen = (unsigned char)i;
1790 table[i].rgbRed = (unsigned char)i;
1792 SetDIBColorTable(window->dc, 0, 255, table);
1795 if(window->flags & CV_WINDOW_AUTOSIZE)
1797 BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
1802 GetClientRect(window->hwnd, &rect);
1803 StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
1804 window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
1807 EndPaint(hwnd, &paint);
1810 else if(window->useGl)
1813 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1818 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1829 icvRemoveWindow(window);
1831 //PostQuitMessage(0);
1835 SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
1839 window->last_key = (int)wParam;
1843 window->width = LOWORD(lParam);
1844 window->height = HIWORD(lParam);
1852 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1856 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1860 if( hg_on_preprocess )
1862 int was_processed = 0;
1863 int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1867 ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
1869 if(hg_on_postprocess)
1871 int was_processed = 0;
1872 int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1881 static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
1883 const int max_name_len = 10;
1884 const char* suffix = "";
1888 if( trackbar->data )
1889 *trackbar->data = pos;
1891 if( trackbar->pos != pos )
1893 trackbar->pos = pos;
1894 if( trackbar->notify2 )
1895 trackbar->notify2(pos, trackbar->userdata);
1896 if( trackbar->notify )
1897 trackbar->notify(pos);
1899 name_len = (int)strlen(trackbar->name);
1901 if( name_len > max_name_len )
1903 int start_len = max_name_len*2/3;
1904 int end_len = max_name_len - start_len - 2;
1905 memcpy( pos_text, trackbar->name, start_len );
1906 memcpy( pos_text + start_len, "...", 3 );
1907 memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
1911 memcpy( pos_text, trackbar->name, name_len + 1);
1914 sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
1915 SetWindowText( trackbar->buddy, pos_text );
1920 static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1922 CvWindow* window = icvWindowByHWND( hwnd );
1924 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1926 // Control messages processing
1929 // Slider processing
1932 HWND slider = (HWND)lParam;
1933 int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
1934 CvTrackbar* trackbar = icvTrackbarByHWND( slider );
1938 if( trackbar->pos != pos )
1939 icvUpdateTrackbar( trackbar, pos );
1942 SetFocus( window->hwnd );
1948 LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1949 int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
1951 if(window->toolbar.rows != rows)
1953 SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1954 CvTrackbar* trackbar = window->toolbar.first;
1956 for( ; trackbar != 0; trackbar = trackbar->next )
1959 SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
1960 (WPARAM)trackbar->id, (LPARAM)&rect);
1961 MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
1962 rect.right - rect.left - HG_BUDDY_WIDTH,
1963 rect.bottom - rect.top, FALSE);
1964 MoveWindow(trackbar->buddy, rect.left, rect.top,
1965 HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
1967 window->toolbar.rows = rows;
1973 return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1978 cvDestroyAllWindows(void)
1980 CvWindow* window = hg_windows;
1984 HWND mainhWnd = window->frame;
1985 HWND hwnd = window->hwnd;
1986 window = window->next;
1988 SendMessage( hwnd, WM_CLOSE, 0, 0 );
1989 SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
1993 static void showSaveDialog(CvWindow* window)
1995 if (!window || !window->image)
2001 if (icvGetBitmapData(window, &sz, &channels, &data))
2002 return; // nothing to save
2004 char szFileName[MAX_PATH] = "";
2005 // try to use window title as file name
2006 GetWindowText(window->frame, szFileName, MAX_PATH);
2009 ZeroMemory(&ofn, sizeof(ofn));
2010 #ifdef OPENFILENAME_SIZE_VERSION_400
2011 // we are not going to use new fields any way
2012 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
2014 ofn.lStructSize = sizeof(ofn);
2016 ofn.hwndOwner = window->hwnd;
2019 "Portable Network Graphics files (*.png)\0*.png\0"
2021 "Windows bitmap (*.bmp;*.dib)\0*.bmp;*.dib\0"
2023 "JPEG files (*.jpeg;*.jpg;*.jpe)\0*.jpeg;*.jpg;*.jpe\0"
2026 "TIFF Files (*.tiff;*.tif)\0*.tiff;*.tif\0"
2029 "JPEG-2000 files (*.jp2)\0*.jp2\0"
2032 "WebP files (*.webp)\0*.webp\0"
2034 "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)\0*.pbm;*.pgm;*.ppm;*.pxm;*.pnm\0"
2036 "OpenEXR Image files (*.exr)\0*.exr\0"
2038 "Radiance HDR (*.hdr;*.pic)\0*.hdr;*.pic\0"
2039 "Sun raster files (*.sr;*.ras)\0*.sr;*.ras\0"
2040 "All Files (*.*)\0*.*\0";
2041 ofn.lpstrFile = szFileName;
2042 ofn.nMaxFile = MAX_PATH;
2043 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_NOCHANGEDIR;
2045 ofn.lpstrDefExt = "png";
2047 ofn.lpstrDefExt = "bmp";
2050 if (GetSaveFileName(&ofn))
2053 cv::flip(cv::Mat(sz.cy, sz.cx, CV_8UC(channels), data, (sz.cx * channels + 3) & -4), tmp, 0);
2054 cv::imwrite(szFileName, tmp);
2059 cvWaitKey( int delay )
2061 int64 time0 = cv::getTickCount();
2062 int64 timeEnd = time0 + (int64)(delay * 0.001f * cv::getTickFrequency());
2068 int is_processed = 0;
2070 if( (delay <= 0) && hg_windows)
2071 GetMessage(&message, 0, 0, 0);
2072 else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
2074 int64 t = cv::getTickCount();
2075 if (t - timeEnd >= 0)
2076 return -1; // no messages and no more time
2081 for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
2083 if( window->hwnd == message.hwnd || window->frame == message.hwnd )
2086 switch(message.message)
2090 DispatchMessage(&message);
2091 return (int)message.wParam;
2094 if( message.wParam == VK_F10 )
2097 return (int)(message.wParam << 16);
2102 TranslateMessage(&message);
2103 if( (message.wParam >= VK_F1 && message.wParam <= VK_F24) ||
2104 message.wParam == VK_HOME || message.wParam == VK_END ||
2105 message.wParam == VK_UP || message.wParam == VK_DOWN ||
2106 message.wParam == VK_LEFT || message.wParam == VK_RIGHT ||
2107 message.wParam == VK_INSERT || message.wParam == VK_DELETE ||
2108 message.wParam == VK_PRIOR || message.wParam == VK_NEXT )
2110 DispatchMessage(&message);
2112 return (int)(message.wParam << 16);
2115 // Intercept Ctrl+C for copy to clipboard
2116 if ('C' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
2117 ::SendMessage(message.hwnd, WM_COPY, 0, 0);
2119 // Intercept Ctrl+S for "save as" dialog
2120 if ('S' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
2121 showSaveDialog(window);
2124 DispatchMessage(&message);
2133 TranslateMessage(&message);
2134 DispatchMessage(&message);
2141 icvFindTrackbarByName( const CvWindow* window, const char* name )
2143 CvTrackbar* trackbar = window->toolbar.first;
2145 for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
2153 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
2154 int* val, int count, CvTrackbarCallback on_notify,
2155 CvTrackbarCallback2 on_notify2, void* userdata )
2159 CV_FUNCNAME( "icvCreateTrackbar" );
2163 char slider_name[32];
2164 CvWindow* window = 0;
2165 CvTrackbar* trackbar = 0;
2168 if( !window_name || !trackbar_name )
2169 CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
2172 CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
2174 window = icvFindWindowByName(window_name);
2178 trackbar = icvFindTrackbarByName(window,trackbar_name);
2182 TBBUTTONINFO tbis = {};
2185 int len = (int)strlen( trackbar_name );
2187 // create toolbar if it is not created yet
2188 if( !window->toolbar.toolbar )
2190 const int default_height = 30;
2192 // CreateToolbarEx is deprecated and forces linking against Comctl32.lib.
2193 window->toolbar.toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
2194 WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE | BTNS_AUTOSIZE | BTNS_BUTTON,
2196 window->frame, NULL, GetModuleHandle(NULL), NULL);
2197 // CreateToolbarEx automatically sends this but CreateWindowEx doesn't.
2198 SendMessage(window->toolbar.toolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
2200 GetClientRect(window->frame, &rect);
2201 MoveWindow( window->toolbar.toolbar, 0, 0,
2202 rect.right - rect.left, default_height, TRUE);
2203 SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
2204 ShowWindow(window->toolbar.toolbar, SW_SHOW);
2206 window->toolbar.first = 0;
2207 window->toolbar.pos = 0;
2208 window->toolbar.rows = 0;
2209 window->toolbar.toolBarProc =
2210 (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);
2212 icvUpdateWindowPos(window);
2214 // Subclassing from toolbar
2215 icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
2216 icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
2219 /* Retrieve current buttons count */
2220 bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
2224 /* If this is not the first button then we need to
2225 separate it from the previous one */
2227 tbs.idCommand = bcount; // Set button id to it's number
2229 tbs.fsStyle = TBSTYLE_SEP;
2230 tbs.fsState = TBSTATE_ENABLED;
2231 SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
2233 // Retrieve current buttons count
2234 bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
2237 /* Add a button which we're going to cover with the slider */
2239 tbs.idCommand = bcount; // Set button id to it's number
2240 tbs.fsState = TBSTATE_ENABLED;
2241 #if 0/*!defined WIN64 && !defined EM64T*/
2246 #ifndef TBSTYLE_AUTOSIZE
2247 #define TBSTYLE_AUTOSIZE 0x0010
2250 #ifndef TBSTYLE_GROUP
2251 #define TBSTYLE_GROUP 0x0004
2253 //tbs.fsStyle = TBSTYLE_AUTOSIZE;
2254 tbs.fsStyle = TBSTYLE_GROUP;
2255 tbs.iString = (INT_PTR)trackbar_text;
2257 SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
2259 /* Adjust button size to the slider */
2260 tbis.cbSize = sizeof(tbis);
2261 tbis.dwMask = TBIF_SIZE;
2263 GetClientRect(window->hwnd, &rect);
2264 tbis.cx = (unsigned short)(rect.right - rect.left);
2266 SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
2267 (WPARAM)tbs.idCommand, (LPARAM)&tbis);
2269 /* Get button pos */
2270 SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
2271 (WPARAM)tbs.idCommand, (LPARAM)&rect);
2273 /* Create a slider */
2274 trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
2275 trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
2276 trackbar->notify = 0;
2277 trackbar->notify2 = 0;
2278 trackbar->parent = window;
2281 trackbar->id = bcount;
2282 trackbar->next = window->toolbar.first;
2283 trackbar->name = (char*)(trackbar + 1);
2284 memcpy( trackbar->name, trackbar_name, len + 1 );
2285 window->toolbar.first = trackbar;
2287 sprintf(slider_name, "Trackbar%p", val);
2288 trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
2289 WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
2290 TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
2291 rect.left + HG_BUDDY_WIDTH, rect.top,
2292 rect.right - rect.left - HG_BUDDY_WIDTH,
2293 rect.bottom - rect.top, window->toolbar.toolbar,
2294 (HMENU)(size_t)bcount, hg_hinstance, 0);
2296 sprintf(slider_name,"Buddy%p", val);
2297 trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
2298 WS_CHILD | SS_RIGHT,
2299 rect.left, rect.top,
2300 HG_BUDDY_WIDTH, rect.bottom - rect.top,
2301 window->toolbar.toolbar, 0, hg_hinstance, 0);
2303 icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
2305 /* Minimize the number of rows */
2306 SendMessage( window->toolbar.toolbar, TB_SETROWS,
2307 MAKEWPARAM(1, FALSE), (LPARAM)&rect );
2312 trackbar->notify = 0;
2313 trackbar->notify2 = 0;
2316 trackbar->maxval = count;
2318 /* Adjust slider parameters */
2319 SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0);
2320 SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)count);
2321 SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
2325 SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
2326 SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
2329 icvUpdateTrackbar( trackbar, pos );
2330 ShowWindow( trackbar->buddy, SW_SHOW );
2331 ShowWindow( trackbar->hwnd, SW_SHOW );
2333 trackbar->notify = on_notify;
2334 trackbar->notify2 = on_notify2;
2335 trackbar->userdata = userdata;
2336 trackbar->data = val;
2338 /* Resize the window to reflect the toolbar resizing*/
2339 icvUpdateWindowPos(window);
2349 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
2350 int* val, int count, CvTrackbarCallback on_notify )
2352 return icvCreateTrackbar( trackbar_name, window_name, val, count,
2357 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
2358 int* val, int count, CvTrackbarCallback2 on_notify2,
2361 return icvCreateTrackbar( trackbar_name, window_name, val, count,
2362 0, on_notify2, userdata );
2366 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
2368 CV_FUNCNAME( "cvSetMouseCallback" );
2372 CvWindow* window = 0;
2375 CV_ERROR( CV_StsNullPtr, "NULL window name" );
2377 window = icvFindWindowByName(window_name);
2381 window->on_mouse = on_mouse;
2382 window->on_mouse_param = param;
2388 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
2392 CV_FUNCNAME( "cvGetTrackbarPos" );
2397 CvTrackbar* trackbar = 0;
2399 if( trackbar_name == 0 || window_name == 0 )
2400 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
2402 window = icvFindWindowByName( window_name );
2404 trackbar = icvFindTrackbarByName( window, trackbar_name );
2407 pos = trackbar->pos;
2415 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
2417 CV_FUNCNAME( "cvSetTrackbarPos" );
2422 CvTrackbar* trackbar = 0;
2424 if( trackbar_name == 0 || window_name == 0 )
2425 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
2427 window = icvFindWindowByName( window_name );
2429 trackbar = icvFindTrackbarByName( window, trackbar_name );
2436 if( pos > trackbar->maxval )
2437 pos = trackbar->maxval;
2439 SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
2440 icvUpdateTrackbar( trackbar, pos );
2447 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
2449 CV_FUNCNAME( "cvSetTrackbarMax" );
2455 CvWindow* window = 0;
2456 CvTrackbar* trackbar = 0;
2457 if (trackbar_name == 0 || window_name == 0)
2459 CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
2462 window = icvFindWindowByName(window_name);
2465 trackbar = icvFindTrackbarByName(window, trackbar_name);
2468 // The position will be min(pos, maxval).
2469 trackbar->maxval = (trackbar->minval>maxval)?trackbar->minval:maxval;
2470 SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
2479 CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)
2481 CV_FUNCNAME( "cvSetTrackbarMin" );
2487 CvWindow* window = 0;
2488 CvTrackbar* trackbar = 0;
2489 if (trackbar_name == 0 || window_name == 0)
2491 CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
2494 window = icvFindWindowByName(window_name);
2497 trackbar = icvFindTrackbarByName(window, trackbar_name);
2500 // The position will be min(pos, maxval).
2501 trackbar->minval = (minval<trackbar->maxval)?minval:trackbar->maxval;
2502 SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)minval);
2511 CV_IMPL void* cvGetWindowHandle( const char* window_name )
2515 CV_FUNCNAME( "cvGetWindowHandle" );
2521 if( window_name == 0 )
2522 CV_ERROR( CV_StsNullPtr, "NULL window name" );
2524 window = icvFindWindowByName( window_name );
2526 hwnd = (void*)window->hwnd;
2534 CV_IMPL const char* cvGetWindowName( void* window_handle )
2536 const char* window_name = "";
2538 CV_FUNCNAME( "cvGetWindowName" );
2544 if( window_handle == 0 )
2545 CV_ERROR( CV_StsNullPtr, "NULL window" );
2547 window = icvWindowByHWND( (HWND)window_handle );
2549 window_name = window->name;
2558 cvSetPreprocessFuncWin32_(const void* callback)
2560 hg_on_preprocess = (CvWin32WindowCallback)callback;
2564 cvSetPostprocessFuncWin32_(const void* callback)
2566 hg_on_postprocess = (CvWin32WindowCallback)callback;