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"
43 #include <windowsx.h> // required for GET_X_LPARAM() and GET_Y_LPARAM() macros
45 #if defined WIN32 || defined _WIN32
48 # pragma GCC diagnostic ignored "-Wmissing-declarations"
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
67 #include "opencv2/highgui.hpp"
71 static const char* trackbar_text =
74 #if defined _M_X64 || defined __x86_64
76 #define icvGetWindowLongPtr GetWindowLongPtr
77 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
78 #define icvGetClassLongPtr GetClassLongPtr
80 #define CV_USERDATA GWLP_USERDATA
81 #define CV_WNDPROC GWLP_WNDPROC
82 #define CV_HCURSOR GCLP_HCURSOR
83 #define CV_HBRBACKGROUND GCLP_HBRBACKGROUND
87 #define icvGetWindowLongPtr GetWindowLong
88 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
89 #define icvGetClassLongPtr GetClassLong
91 #define CV_USERDATA GWL_USERDATA
92 #define CV_WNDPROC GWL_WNDPROC
93 #define CV_HCURSOR GCL_HCURSOR
94 #define CV_HBRBACKGROUND GCL_HBRBACKGROUND
98 #ifndef WM_MOUSEHWHEEL
99 #define WM_MOUSEHWHEEL 0x020E
102 static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
104 assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
106 BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
108 memset( bmih, 0, sizeof(*bmih));
109 bmih->biSize = sizeof(BITMAPINFOHEADER);
110 bmih->biWidth = width;
111 bmih->biHeight = origin ? abs(height) : -abs(height);
113 bmih->biBitCount = (unsigned short)bpp;
114 bmih->biCompression = BI_RGB;
118 RGBQUAD* palette = bmi->bmiColors;
120 for( i = 0; i < 256; i++ )
122 palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
123 palette[i].rgbReserved = 0;
130 typedef struct CvTrackbar
142 void (*notify2)(int, void*);
149 typedef struct CvWindow
162 int status;//0 normal, 1 fullscreen (YV)
164 CvMouseCallback on_mouse;
165 void* on_mouse_param;
186 CvOpenGlDrawCallback glDrawCallback;
192 #define HG_BUDDY_WIDTH 130
195 #define TBIF_SIZE 0x40
198 #ifndef TB_SETBUTTONINFO
199 #define TB_SETBUTTONINFO (WM_USER + 66)
202 #ifndef TBM_GETTOOLTIPS
203 #define TBM_GETTOOLTIPS (WM_USER + 30)
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 );
211 static CvWindow* hg_windows = 0;
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;
217 static const char* highGUIclassName = "HighGUI class";
218 static const char* mainHighGUIclassName = "Main HighGUI class";
220 static void icvCleanupHighgui()
222 cvDestroyAllWindows();
223 UnregisterClass(highGUIclassName, hg_hinstance);
224 UnregisterClass(mainHighGUIclassName, hg_hinstance);
227 CV_IMPL int cvInitSystem( int, char** )
229 static int wasInitialized = 0;
231 // check initialization status
232 if( !wasInitialized )
234 // Initialize the stogare
237 // Register the class
239 wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
240 wndc.lpfnWndProc = WindowProc;
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);
250 RegisterClass(&wndc);
252 wndc.lpszClassName = mainHighGUIclassName;
253 wndc.lpszMenuName = mainHighGUIclassName;
254 wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
255 wndc.lpfnWndProc = MainWindowProc;
257 RegisterClass(&wndc);
258 atexit( icvCleanupHighgui );
266 CV_IMPL int cvStartWindowThread(){
270 static CvWindow* icvFindWindowByName( const char* name )
272 CvWindow* window = hg_windows;
274 for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
281 static CvWindow* icvWindowByHWND( HWND hwnd )
283 CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
284 return window != 0 && hg_windows != 0 &&
285 window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
289 static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
291 CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
292 return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
293 trackbar->hwnd == hwnd ? trackbar : 0;
297 static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
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.
303 icvLoadWindowPos( const char* name, CvRect& rect )
307 strcpy( szKey, icvWindowPosRootKey );
308 strcat( szKey, name );
310 rect.x = rect.y = CW_USEDEFAULT;
311 rect.width = rect.height = 320;
313 if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
315 // Yes we are installed.
317 DWORD dwSize = sizeof(int);
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);
324 if( rect.x != (int)CW_USEDEFAULT && (rect.x < -200 || rect.x > 3000) )
326 if( rect.y != (int)CW_USEDEFAULT && (rect.y < -200 || rect.y > 3000) )
329 if( rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000) )
331 if( rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000) )
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
343 icvSaveWindowPos( const char* name, CvRect rect )
345 static const DWORD MAX_RECORD_COUNT = 100;
349 strcpy( szKey, icvWindowPosRootKey );
350 strcat( szKey, name );
352 if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
356 FILETIME oldestTime = { UINT_MAX, UINT_MAX };
357 char oldestKey[1024];
358 char currentKey[1024];
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 )
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 )
374 if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
375 (oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
376 oldestTime.dwLowDateTime > accesstime.dwLowDateTime) )
378 oldestTime = accesstime;
379 strcpy( oldestKey, currentKey );
383 if( count >= MAX_RECORD_COUNT )
384 RegDeleteKey( hroot, oldestKey );
385 RegCloseKey( hroot );
387 if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
393 if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
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));
404 double cvGetModeWindow_W32(const char* name)//YV
408 CV_FUNCNAME( "cvGetModeWindow_W32" );
415 CV_ERROR( CV_StsNullPtr, "NULL name string" );
417 window = icvFindWindowByName( name );
419 EXIT; // keep silence here
421 result = window->status;
427 void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
429 CV_FUNCNAME( "cvSetModeWindow_W32" );
436 CV_ERROR( CV_StsNullPtr, "NULL name string" );
438 window = icvFindWindowByName( name );
440 CV_ERROR( CV_StsNullPtr, "NULL window" );
442 if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
446 DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE);
449 if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
451 icvLoadWindowPos(window->name,position );
452 SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);
454 SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
455 window->status=CV_WINDOW_NORMAL;
460 if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
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 );
468 //Look at coordinate for fullscreen
471 hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
473 mi.cbSize = sizeof(mi);
474 GetMonitorInfo(hMonitor, &mi);
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);
481 SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
482 window->status=CV_WINDOW_FULLSCREEN;
491 void cv::setWindowTitle(const String& winname, const String& title)
493 CvWindow* window = icvFindWindowByName(winname.c_str());
497 namedWindow(winname);
498 window = icvFindWindowByName(winname.c_str());
502 CV_Error(Error::StsNullPtr, "NULL window");
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()));
508 double cvGetPropWindowAutoSize_W32(const char* name)
512 CV_FUNCNAME( "cvSetCloseCallback" );
519 CV_ERROR( CV_StsNullPtr, "NULL name string" );
521 window = icvFindWindowByName( name );
523 EXIT; // keep silence here
525 result = window->flags & CV_WINDOW_AUTOSIZE;
532 double cvGetRatioWindow_W32(const char* name)
536 CV_FUNCNAME( "cvGetRatioWindow_W32" );
543 CV_ERROR( CV_StsNullPtr, "NULL name string" );
545 window = icvFindWindowByName( name );
547 EXIT; // keep silence here
549 result = static_cast<double>(window->width) / window->height;
556 double cvGetOpenGlProp_W32(const char* name)
561 CV_FUNCNAME( "cvGetOpenGlProp_W32" );
568 CV_ERROR( CV_StsNullPtr, "NULL name string" );
570 window = icvFindWindowByName( name );
572 EXIT; // keep silence here
574 result = window->useGl;
590 void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl)
592 CV_FUNCNAME( "createGlContext" );
600 static PIXELFORMATDESCRIPTOR pfd =
602 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
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
619 0, 0, 0 // Layer Masks Ignored
624 CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
626 PixelFormat = ChoosePixelFormat(hGLDC, &pfd);
628 CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" );
630 if (!SetPixelFormat(hGLDC, PixelFormat, &pfd))
631 CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" );
633 hGLRC = wglCreateContext(hGLDC);
635 CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" );
637 if (!wglMakeCurrent(hGLDC, hGLRC))
638 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
645 void releaseGlContext(CvWindow* window)
647 //CV_FUNCNAME( "releaseGlContext" );
653 wglDeleteContext(window->hGLRC);
654 window->hGLRC = NULL;
659 ReleaseDC(window->hwnd, window->dc);
663 window->useGl = false;
668 void drawGl(CvWindow* window)
670 CV_FUNCNAME( "drawGl" );
674 if (!wglMakeCurrent(window->dc, window->hGLRC))
675 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
677 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
679 if (window->glDrawCallback)
680 window->glDrawCallback(window->glDrawData);
682 if (!SwapBuffers(window->dc))
683 CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" );
688 void resizeGl(CvWindow* window)
690 CV_FUNCNAME( "resizeGl" );
694 if (!wglMakeCurrent(window->dc, window->hGLRC))
695 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
697 glViewport(0, 0, window->width, window->height);
703 #endif // HAVE_OPENGL
706 CV_IMPL int cvNamedWindow( const char* name, int flags )
709 CV_FUNCNAME( "cvNamedWindow" );
715 DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
727 CV_ERROR( CV_StsNullPtr, "NULL name string" );
729 // Check the name in the storage
730 window = icvFindWindowByName( name );
737 if( !(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
738 defStyle |= WS_SIZEBOX;
740 icvLoadWindowPos( name, rect );
742 mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
743 rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
745 CV_ERROR( CV_StsError, "Frame window can not be created" );
747 ShowWindow(mainhWnd, SW_SHOW);
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);
752 CV_ERROR( CV_StsError, "Frame window can not be created" );
755 if (flags & CV_WINDOW_OPENGL)
756 CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
762 if (flags & CV_WINDOW_OPENGL)
763 createGlContext(hWnd, hGLDC, hGLRC, useGl);
766 ShowWindow(hWnd, SW_SHOW);
768 len = (int)strlen(name);
769 CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
771 window->signature = CV_WINDOW_MAGIC_VAL;
773 window->frame = mainhWnd;
774 window->name = (char*)(window + 1);
775 memcpy( window->name, name, len + 1 );
776 window->flags = flags;
780 window->dc = CreateCompatibleDC(0);
784 window->dc = CreateCompatibleDC(0);
786 window->useGl = false;
791 window->hGLRC = hGLRC;
792 window->useGl = true;
795 window->glDrawCallback = 0;
796 window->glDrawData = 0;
799 window->last_key = 0;
800 window->status = CV_WINDOW_NORMAL;//YV
802 window->on_mouse = 0;
803 window->on_mouse_param = 0;
805 memset( &window->toolbar, 0, sizeof(window->toolbar));
807 window->next = hg_windows;
810 hg_windows->prev = window;
812 icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
813 icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
815 // Recalculate window pos
816 icvUpdateWindowPos( window );
826 CV_IMPL void cvSetOpenGlContext(const char* name)
828 CV_FUNCNAME( "cvSetOpenGlContext" );
835 CV_ERROR( CV_StsNullPtr, "NULL name string" );
837 window = icvFindWindowByName( name );
839 CV_ERROR( CV_StsNullPtr, "NULL window" );
842 CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
844 if (!wglMakeCurrent(window->dc, window->hGLRC))
845 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
850 CV_IMPL void cvUpdateWindow(const char* name)
852 CV_FUNCNAME( "cvUpdateWindow" );
859 CV_ERROR( CV_StsNullPtr, "NULL name string" );
861 window = icvFindWindowByName( name );
865 InvalidateRect(window->hwnd, 0, 0);
870 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
872 CV_FUNCNAME( "cvCreateOpenGLCallback" );
879 CV_ERROR( CV_StsNullPtr, "NULL name string" );
881 window = icvFindWindowByName( name );
886 CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
888 window->glDrawCallback = callback;
889 window->glDrawData = userdata;
894 #endif // HAVE_OPENGL
896 static void icvRemoveWindow( CvWindow* window )
898 CvTrackbar* trackbar = NULL;
899 RECT wrect={0,0,0,0};
903 releaseGlContext(window);
907 GetWindowRect( window->frame, &wrect );
909 icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
910 wrect.right-wrect.left, wrect.bottom-wrect.top) );
913 icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
915 icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
917 if( window->toolbar.toolbar )
918 icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0);
921 window->prev->next = window->next;
923 hg_windows = window->next;
926 window->next->prev = window->prev;
928 window->prev = window->next = 0;
930 if( window->dc && window->image )
931 DeleteObject(SelectObject(window->dc,window->image));
934 DeleteDC(window->dc);
936 for( trackbar = window->toolbar.first; trackbar != 0; )
938 CvTrackbar* next = trackbar->next;
941 icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
951 CV_IMPL void cvDestroyWindow( const char* name )
953 CV_FUNCNAME( "cvDestroyWindow" );
961 CV_ERROR( CV_StsNullPtr, "NULL name string" );
963 window = icvFindWindowByName( name );
967 mainhWnd = window->frame;
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 ...
977 static void icvScreenToClient( HWND hwnd, RECT* rect )
982 ScreenToClient(hwnd, &p);
983 OffsetRect( rect, p.x - rect->left, p.y - rect->top );
987 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
988 static RECT icvCalcWindowRect( CvWindow* window )
990 const int gutter = 1;
991 RECT crect, trect, rect;
995 GetClientRect(window->frame, &crect);
996 if(window->toolbar.toolbar)
998 GetWindowRect(window->toolbar.toolbar, &trect);
999 icvScreenToClient(window->frame, &trect);
1000 SubtractRect( &rect, &crect, &trect);
1006 rect.left += gutter;
1007 rect.bottom -= gutter;
1008 rect.right -= gutter;
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 )
1018 HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
1020 size->cx = size->cy = 0;
1026 if (GetObject(h, sizeof(bmp), &bmp) == 0)
1031 size->cx = abs(bmp.bmWidth);
1032 size->cy = abs(bmp.bmHeight);
1036 *channels = bmp.bmBitsPixel/8;
1045 static void icvUpdateWindowPos( CvWindow* window )
1050 if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
1054 icvGetBitmapData( window, &size, 0, 0 );
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++)
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 );
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 );
1079 cvShowImage( const char* name, const CvArr* arr )
1081 CV_FUNCNAME( "cvShowImage" );
1086 SIZE size = { 0, 0 };
1089 const int channels0 = 3;
1091 CvMat stub, dst, *image;
1092 bool changed_size = false; // philipg
1095 CV_ERROR( CV_StsNullPtr, "NULL name" );
1097 window = icvFindWindowByName(name);
1100 cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
1101 window = icvFindWindowByName(name);
1104 if( !window || !arr )
1105 EXIT; // keep silence here.
1107 if( CV_IS_IMAGE_HDR( arr ))
1108 origin = ((IplImage*)arr)->origin;
1110 CV_CALL( image = cvGetMat( arr, &stub ));
1115 cv::imshow(name, cv::cvarrToMat(image));
1121 // if there is something wrong with these system calls, we cannot display image...
1122 if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
1125 if( size.cx != image->width || size.cy != image->height || channels != channels0 )
1127 changed_size = true;
1129 uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
1130 BITMAPINFO* binfo = (BITMAPINFO*)buffer;
1132 DeleteObject( SelectObject( window->dc, window->image ));
1135 size.cx = image->width;
1136 size.cy = image->height;
1137 channels = channels0;
1139 FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
1141 window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
1142 DIB_RGB_COLORS, &dst_ptr, 0, 0));
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 );
1149 // ony resize window if needed
1151 icvUpdateWindowPos(window);
1152 InvalidateRect(window->hwnd, 0, 0);
1153 // philipg: this is not needed and just slows things down
1154 // UpdateWindow(window->hwnd);
1161 cvShowImageHWND(HWND w_hWnd, const CvArr* arr)
1163 CV_FUNCNAME( "cvShowImageHWND" );
1167 SIZE size = { 0, 0 };
1170 const int channels0 = 3;
1172 CvMat stub, dst, *image;
1173 bool changed_size = false;
1174 BITMAPINFO tempbinfo;
1182 hdc = GetDC(w_hWnd);
1184 if( CV_IS_IMAGE_HDR( arr ) )
1185 origin = ((IplImage*)arr)->origin;
1187 CV_CALL( image = cvGetMat( arr, &stub ) );
1194 HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );
1198 if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
1201 channels = bmp.bmBitsPixel/8;
1202 dst_ptr = bmp.bmBits;
1205 if( size.cx != image->width || size.cy != image->height || channels != channels0 )
1207 changed_size = true;
1209 uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
1210 BITMAPINFO* binfo = (BITMAPINFO*)buffer;
1212 BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
1213 CV_Assert( FALSE != bDeleteObj );
1215 size.cx = image->width;
1216 size.cy = image->height;
1217 channels = channels0;
1219 FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
1221 SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
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 );
1227 // Image stretching to fit the window
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 );
1232 // ony resize window if needed
1233 InvalidateRect(w_hWnd, 0, 0);
1239 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1241 CV_FUNCNAME( "cvResizeWindow" );
1250 CV_ERROR( CV_StsNullPtr, "NULL name" );
1252 window = icvFindWindowByName(name);
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++)
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);
1271 rect = icvCalcWindowRect(window);
1272 MoveWindow(window->hwnd, rect.left, rect.top,
1273 rect.right - rect.left + 1, rect.bottom - rect.top + 1, TRUE);
1279 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1281 CV_FUNCNAME( "cvMoveWindow" );
1289 CV_ERROR( CV_StsNullPtr, "NULL name" );
1291 window = icvFindWindowByName(name);
1295 GetWindowRect( window->frame, &rect );
1296 MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
1302 static LRESULT CALLBACK
1303 MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1305 CvWindow* window = icvWindowByHWND( hwnd );
1307 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1312 ::SendMessage(window->hwnd, uMsg, wParam, lParam);
1317 icvRemoveWindow(window);
1319 //PostQuitMessage(0);
1322 case WM_GETMINMAXINFO:
1323 if( !(window->flags & CV_WINDOW_AUTOSIZE) )
1325 MINMAXINFO* minmax = (MINMAXINFO*)lParam;
1327 LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);
1329 minmax->ptMinTrackSize.y = 100;
1330 minmax->ptMinTrackSize.x = 100;
1332 if( window->toolbar.first )
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);
1342 case WM_WINDOWPOSCHANGED:
1344 WINDOWPOS* pos = (WINDOWPOS*)lParam;
1346 // Update the toolbar pos/size
1347 if(window->toolbar.toolbar)
1350 GetWindowRect(window->toolbar.toolbar, &rect);
1351 MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
1354 if(!(window->flags & CV_WINDOW_AUTOSIZE))
1355 icvUpdateWindowPos(window);
1360 case WM_WINDOWPOSCHANGING:
1362 // Snap window to screen edges with multi-monitor support. // Adi Shavit
1363 LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
1366 GetWindowRect(window->frame, &rect);
1369 hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
1372 mi.cbSize = sizeof(mi);
1373 GetMonitorInfo(hMonitor, &mi);
1375 const int SNAP_DISTANCE = 15;
1377 if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
1378 pos->x = mi.rcMonitor.left; // snap to left edge
1380 if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
1381 pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge
1383 if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
1384 pos->y = mi.rcMonitor.top; // snap to top edge
1386 if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
1387 pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
1391 if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
1392 SetFocus(window->hwnd);
1396 case WM_MOUSEHWHEEL:
1397 if( window->on_mouse )
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);
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);
1412 pt.x = GET_X_LPARAM( lParam );
1413 pt.y = GET_Y_LPARAM( lParam );
1414 ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates.
1417 GetClientRect( window->hwnd, &rect );
1420 icvGetBitmapData( window, &size, 0, 0 );
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 );
1431 HRGN rgn, rgn1, rgn2;
1433 HDC hdc = (HDC)wParam;
1434 GetWindowRect(window->hwnd, &cr);
1435 icvScreenToClient(window->frame, &cr);
1436 if(window->toolbar.toolbar)
1438 GetWindowRect(window->toolbar.toolbar, &tr);
1439 icvScreenToClient(window->frame, &tr);
1442 tr.left = tr.top = tr.right = tr.bottom = 0;
1444 GetClientRect(window->frame, &wrc);
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);
1452 if(ret != NULLREGION && ret != ERROR)
1453 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
1462 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1466 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1468 CvWindow* window = icvWindowByHWND(hwnd);
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);
1474 // Process the message
1479 if (!::OpenClipboard(hwnd) )
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.
1490 if (!::EmptyClipboard())
1496 // Get window device context
1497 if (0 == (hDC = ::GetDC(hwnd)))
1500 // Create another DC compatible with hDC
1501 if (0 == (memDC = ::CreateCompatibleDC( hDC )))
1504 // Determine the bitmap's dimensions
1507 icvGetBitmapData( window, &size, &nchannels, 0 );
1509 // Create bitmap to draw on and it in the new DC
1510 if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy)))
1513 if (!::SelectObject( memDC, memBM ))
1516 // Begin drawing to DC
1517 if (!::SetStretchBltMode(memDC, COLORONCOLOR))
1521 if( 1 == nchannels )
1523 for(int i = 0; i < 256; ++i)
1525 table[i].rgbBlue = (unsigned char)i;
1526 table[i].rgbGreen = (unsigned char)i;
1527 table[i].rgbRed = (unsigned char)i;
1529 if (!::SetDIBColorTable(window->dc, 0, 255, table))
1533 // The image copied to the clipboard will be in its original size, regardless if the window itself was resized.
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 ))
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"
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);
1552 case WM_WINDOWPOSCHANGING:
1554 LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
1555 RECT rect = icvCalcWindowRect(window);
1558 pos->cx = rect.right - rect.left + 1;
1559 pos->cy = rect.bottom - rect.top + 1;
1563 case WM_LBUTTONDOWN:
1564 case WM_RBUTTONDOWN:
1565 case WM_MBUTTONDOWN:
1566 case WM_LBUTTONDBLCLK:
1567 case WM_RBUTTONDBLCLK:
1568 case WM_MBUTTONDBLCLK:
1573 if( window->on_mouse )
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 :
1593 if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
1595 if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
1598 pt.x = GET_X_LPARAM( lParam );
1599 pt.y = GET_Y_LPARAM( lParam );
1601 if (window->flags & CV_WINDOW_AUTOSIZE)
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 );
1607 // Full window is displayed using different size. Scale coordinates to match underlying positions.
1611 GetClientRect( window->hwnd, &rect );
1612 icvGetBitmapData( window, &size, 0, 0 );
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 );
1622 if(window->image != 0)
1630 // Determine the bitmap's dimensions
1631 icvGetBitmapData( window, &size, &nchannels, 0 );
1633 hdc = BeginPaint(hwnd, &paint);
1634 SetStretchBltMode(hdc, COLORONCOLOR);
1636 if( nchannels == 1 )
1639 for(i = 0; i < 256; i++)
1641 table[i].rgbBlue = (unsigned char)i;
1642 table[i].rgbGreen = (unsigned char)i;
1643 table[i].rgbRed = (unsigned char)i;
1645 SetDIBColorTable(window->dc, 0, 255, table);
1648 if(window->flags & CV_WINDOW_AUTOSIZE)
1650 BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
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 );
1660 EndPaint(hwnd, &paint);
1663 else if(window->useGl)
1666 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1671 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1682 icvRemoveWindow(window);
1684 //PostQuitMessage(0);
1688 SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
1692 window->last_key = (int)wParam;
1696 window->width = LOWORD(lParam);
1697 window->height = HIWORD(lParam);
1705 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1709 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1713 if( hg_on_preprocess )
1715 int was_processed = 0;
1716 int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1720 ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
1722 if(hg_on_postprocess)
1724 int was_processed = 0;
1725 int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1734 static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
1736 const int max_name_len = 10;
1737 const char* suffix = "";
1741 if( trackbar->data )
1742 *trackbar->data = pos;
1744 if( trackbar->pos != pos )
1746 trackbar->pos = pos;
1747 if( trackbar->notify2 )
1748 trackbar->notify2(pos, trackbar->userdata);
1749 if( trackbar->notify )
1750 trackbar->notify(pos);
1752 name_len = (int)strlen(trackbar->name);
1754 if( name_len > max_name_len )
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 );
1764 memcpy( pos_text, trackbar->name, name_len + 1);
1767 sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
1768 SetWindowText( trackbar->buddy, pos_text );
1773 static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1775 CvWindow* window = icvWindowByHWND( hwnd );
1777 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1779 // Control messages processing
1782 // Slider processing
1785 HWND slider = (HWND)lParam;
1786 int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
1787 CvTrackbar* trackbar = icvTrackbarByHWND( slider );
1791 if( trackbar->pos != pos )
1792 icvUpdateTrackbar( trackbar, pos );
1795 SetFocus( window->hwnd );
1801 LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1802 int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
1804 if(window->toolbar.rows != rows)
1806 SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1807 CvTrackbar* trackbar = window->toolbar.first;
1809 for( ; trackbar != 0; trackbar = trackbar->next )
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);
1820 window->toolbar.rows = rows;
1826 return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1831 cvDestroyAllWindows(void)
1833 CvWindow* window = hg_windows;
1837 HWND mainhWnd = window->frame;
1838 HWND hwnd = window->hwnd;
1839 window = window->next;
1841 SendMessage( hwnd, WM_CLOSE, 0, 0 );
1842 SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
1846 static void showSaveDialog(CvWindow* window)
1848 if (!window || !window->image)
1854 if (icvGetBitmapData(window, &sz, &channels, &data))
1855 return; // nothing to save
1857 char szFileName[MAX_PATH] = "";
1858 // try to use window title as file name
1859 GetWindowText(window->frame, szFileName, MAX_PATH);
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;
1867 ofn.lStructSize = sizeof(ofn);
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";
1886 if (GetSaveFileName(&ofn))
1888 cv::Mat tmp; cv::flip(cv::Mat(sz.cy, sz.cx, CV_8UC(channels), data), tmp, 0);
1889 cv::imwrite(szFileName, tmp);
1894 cvWaitKey( int delay )
1896 int time0 = GetTickCount();
1902 int is_processed = 0;
1904 if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 )
1908 GetMessage(&message, 0, 0, 0);
1909 else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
1915 for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
1917 if( window->hwnd == message.hwnd || window->frame == message.hwnd )
1920 switch(message.message)
1924 DispatchMessage(&message);
1925 return (int)message.wParam;
1928 if( message.wParam == VK_F10 )
1931 return (int)(message.wParam << 16);
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 )
1944 DispatchMessage(&message);
1946 return (int)(message.wParam << 16);
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);
1953 // Intercept Ctrl+S for "save as" dialog
1954 if ('S' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
1955 showSaveDialog(window);
1958 DispatchMessage(&message);
1967 TranslateMessage(&message);
1968 DispatchMessage(&message);
1975 icvFindTrackbarByName( const CvWindow* window, const char* name )
1977 CvTrackbar* trackbar = window->toolbar.first;
1979 for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
1987 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
1988 int* val, int count, CvTrackbarCallback on_notify,
1989 CvTrackbarCallback2 on_notify2, void* userdata )
1993 CV_FUNCNAME( "icvCreateTrackbar" );
1997 char slider_name[32];
1998 CvWindow* window = 0;
1999 CvTrackbar* trackbar = 0;
2002 if( !window_name || !trackbar_name )
2003 CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
2006 CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
2008 window = icvFindWindowByName(window_name);
2012 trackbar = icvFindTrackbarByName(window,trackbar_name);
2016 TBBUTTONINFO tbis = {0};
2019 int len = (int)strlen( trackbar_name );
2021 // create toolbar if it is not created yet
2022 if( !window->toolbar.toolbar )
2024 const int default_height = 30;
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,
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);
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);
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);
2046 icvUpdateWindowPos(window);
2048 // Subclassing from toolbar
2049 icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
2050 icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
2053 /* Retrieve current buttons count */
2054 bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
2058 /* If this is not the first button then we need to
2059 separate it from the previous one */
2061 tbs.idCommand = bcount; // Set button id to it's number
2063 tbs.fsStyle = TBSTYLE_SEP;
2064 tbs.fsState = TBSTATE_ENABLED;
2065 SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
2067 // Retrieve current buttons count
2068 bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
2071 /* Add a button which we're going to cover with the slider */
2073 tbs.idCommand = bcount; // Set button id to it's number
2074 tbs.fsState = TBSTATE_ENABLED;
2075 #if 0/*!defined WIN64 && !defined EM64T*/
2080 #ifndef TBSTYLE_AUTOSIZE
2081 #define TBSTYLE_AUTOSIZE 0x0010
2084 #ifndef TBSTYLE_GROUP
2085 #define TBSTYLE_GROUP 0x0004
2087 //tbs.fsStyle = TBSTYLE_AUTOSIZE;
2088 tbs.fsStyle = TBSTYLE_GROUP;
2089 tbs.iString = (INT_PTR)trackbar_text;
2091 SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
2093 /* Adjust button size to the slider */
2094 tbis.cbSize = sizeof(tbis);
2095 tbis.dwMask = TBIF_SIZE;
2097 GetClientRect(window->hwnd, &rect);
2098 tbis.cx = (unsigned short)(rect.right - rect.left);
2100 SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
2101 (WPARAM)tbs.idCommand, (LPARAM)&tbis);
2103 /* Get button pos */
2104 SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
2105 (WPARAM)tbs.idCommand, (LPARAM)&rect);
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;
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;
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);
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);
2137 icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
2139 /* Minimize the number of rows */
2140 SendMessage( window->toolbar.toolbar, TB_SETROWS,
2141 MAKEWPARAM(1, FALSE), (LPARAM)&rect );
2146 trackbar->notify = 0;
2147 trackbar->notify2 = 0;
2150 trackbar->maxval = count;
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 );
2159 SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
2160 SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
2163 icvUpdateTrackbar( trackbar, pos );
2164 ShowWindow( trackbar->buddy, SW_SHOW );
2165 ShowWindow( trackbar->hwnd, SW_SHOW );
2167 trackbar->notify = on_notify;
2168 trackbar->notify2 = on_notify2;
2169 trackbar->userdata = userdata;
2170 trackbar->data = val;
2172 /* Resize the window to reflect the toolbar resizing*/
2173 icvUpdateWindowPos(window);
2183 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
2184 int* val, int count, CvTrackbarCallback on_notify )
2186 return icvCreateTrackbar( trackbar_name, window_name, val, count,
2191 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
2192 int* val, int count, CvTrackbarCallback2 on_notify2,
2195 return icvCreateTrackbar( trackbar_name, window_name, val, count,
2196 0, on_notify2, userdata );
2200 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
2202 CV_FUNCNAME( "cvSetMouseCallback" );
2206 CvWindow* window = 0;
2209 CV_ERROR( CV_StsNullPtr, "NULL window name" );
2211 window = icvFindWindowByName(window_name);
2215 window->on_mouse = on_mouse;
2216 window->on_mouse_param = param;
2222 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
2226 CV_FUNCNAME( "cvGetTrackbarPos" );
2231 CvTrackbar* trackbar = 0;
2233 if( trackbar_name == 0 || window_name == 0 )
2234 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
2236 window = icvFindWindowByName( window_name );
2238 trackbar = icvFindTrackbarByName( window, trackbar_name );
2241 pos = trackbar->pos;
2249 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
2251 CV_FUNCNAME( "cvSetTrackbarPos" );
2256 CvTrackbar* trackbar = 0;
2258 if( trackbar_name == 0 || window_name == 0 )
2259 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
2261 window = icvFindWindowByName( window_name );
2263 trackbar = icvFindTrackbarByName( window, trackbar_name );
2270 if( pos > trackbar->maxval )
2271 pos = trackbar->maxval;
2273 SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
2274 icvUpdateTrackbar( trackbar, pos );
2281 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
2283 CV_FUNCNAME( "cvSetTrackbarMax" );
2289 CvWindow* window = 0;
2290 CvTrackbar* trackbar = 0;
2291 if (trackbar_name == 0 || window_name == 0)
2293 CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
2296 window = icvFindWindowByName(window_name);
2299 trackbar = icvFindTrackbarByName(window, trackbar_name);
2302 // The position will be min(pos, maxval).
2303 trackbar->maxval = maxval;
2304 SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
2313 CV_IMPL void* cvGetWindowHandle( const char* window_name )
2317 CV_FUNCNAME( "cvGetWindowHandle" );
2323 if( window_name == 0 )
2324 CV_ERROR( CV_StsNullPtr, "NULL window name" );
2326 window = icvFindWindowByName( window_name );
2328 hwnd = (void*)window->hwnd;
2336 CV_IMPL const char* cvGetWindowName( void* window_handle )
2338 const char* window_name = "";
2340 CV_FUNCNAME( "cvGetWindowName" );
2346 if( window_handle == 0 )
2347 CV_ERROR( CV_StsNullPtr, "NULL window" );
2349 window = icvWindowByHWND( (HWND)window_handle );
2351 window_name = window->name;
2360 cvSetPreprocessFuncWin32_(const void* callback)
2362 hg_on_preprocess = (CvWin32WindowCallback)callback;
2366 cvSetPostprocessFuncWin32_(const void* callback)
2368 hg_on_postprocess = (CvWin32WindowCallback)callback;