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.
44 #if defined WIN32 || defined WIN64
47 #pragma warning( disable: 4710 )
57 static const char* trackbar_text =
60 #if defined WIN64 || defined EM64T
62 #define icvGetWindowLongPtr GetWindowLongPtr
63 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
64 #define icvGetClassLongPtr GetClassLongPtr
66 #define CV_USERDATA GWLP_USERDATA
67 #define CV_WNDPROC GWLP_WNDPROC
68 #define CV_HCURSOR GCLP_HCURSOR
69 #define CV_HBRBACKGROUND GCLP_HBRBACKGROUND
73 #define icvGetWindowLongPtr GetWindowLong
74 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
75 #define icvGetClassLongPtr GetClassLong
77 #define CV_USERDATA GWL_USERDATA
78 #define CV_WNDPROC GWL_WNDPROC
79 #define CV_HCURSOR GCL_HCURSOR
80 #define CV_HBRBACKGROUND GCL_HBRBACKGROUND
84 void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
86 assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
88 BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
90 memset( bmih, 0, sizeof(*bmih));
91 bmih->biSize = sizeof(BITMAPINFOHEADER);
92 bmih->biWidth = width;
93 bmih->biHeight = origin ? abs(height) : -abs(height);
95 bmih->biBitCount = (unsigned short)bpp;
96 bmih->biCompression = BI_RGB;
100 RGBQUAD* palette = bmi->bmiColors;
102 for( i = 0; i < 256; i++ )
104 palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
105 palette[i].rgbReserved = 0;
112 typedef struct CvTrackbar
129 typedef struct CvWindow
143 CvMouseCallback on_mouse;
144 void* on_mouse_param;
159 #define HG_BUDDY_WIDTH 130
162 #define TBIF_SIZE 0x40
165 #ifndef TB_SETBUTTONINFO
166 #define TB_SETBUTTONINFO (WM_USER + 66)
169 #ifndef TBM_GETTOOLTIPS
170 #define TBM_GETTOOLTIPS (WM_USER + 30)
173 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
174 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
175 static LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
176 static void icvUpdateWindowPos( CvWindow* window );
178 static CvWindow* hg_windows = 0;
179 static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
180 static HINSTANCE hg_hinstance = 0;
182 static const char* highGUIclassName = "HighGUI class";
183 static const char* mainHighGUIclassName = "Main HighGUI class";
185 static void icvCleanupHighgui()
187 cvDestroyAllWindows();
188 UnregisterClass(highGUIclassName, hg_hinstance);
189 UnregisterClass(mainHighGUIclassName, hg_hinstance);
192 CV_IMPL int cvInitSystem( int, char** )
194 static int wasInitialized = 0;
196 // check initialization status
197 if( !wasInitialized )
199 // Initialize the stogare
202 // Register the class
204 wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
205 wndc.lpfnWndProc = WindowProc;
208 wndc.hInstance = hg_hinstance;
209 wndc.lpszClassName = highGUIclassName;
210 wndc.lpszMenuName = highGUIclassName;
211 wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
212 wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
213 wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
215 RegisterClass(&wndc);
217 wndc.lpszClassName = mainHighGUIclassName;
218 wndc.lpszMenuName = mainHighGUIclassName;
219 wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
220 wndc.lpfnWndProc = MainWindowProc;
222 RegisterClass(&wndc);
223 atexit( icvCleanupHighgui );
231 CV_IMPL int cvStartWindowThread(){
235 static CvWindow* icvFindWindowByName( const char* name )
237 CvWindow* window = hg_windows;
239 for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
246 static CvWindow* icvWindowByHWND( HWND hwnd )
248 CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
249 return window != 0 && hg_windows != 0 &&
250 window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
254 static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
256 CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
257 return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
258 trackbar->hwnd == hwnd ? trackbar : 0;
262 static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
264 // Window positions saving/loading added by Philip Gruebele.
265 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
266 // Restores the window position from the registry saved position.
268 icvLoadWindowPos( const char* name, CvRect& rect )
272 strcpy( szKey, icvWindowPosRootKey );
273 strcat( szKey, name );
275 rect.x = rect.y = CW_USEDEFAULT;
276 rect.width = rect.height = 320;
278 if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
280 // Yes we are installed.
282 DWORD dwSize = sizeof(int);
284 RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize);
285 RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize);
286 RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize);
287 RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize);
289 if( rect.x != (int)CW_USEDEFAULT && (rect.x < -200 || rect.x > 3000) )
291 if( rect.y != (int)CW_USEDEFAULT && (rect.y < -200 || rect.y > 3000) )
294 if( rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000) )
296 if( rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000) )
304 // Window positions saving/loading added by Philip Gruebele.
305 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
306 // philipg. Saves the window position in the registry
308 icvSaveWindowPos( const char* name, CvRect rect )
310 static const DWORD MAX_RECORD_COUNT = 100;
314 strcpy( szKey, icvWindowPosRootKey );
315 strcat( szKey, name );
317 if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
321 FILETIME oldestTime = { UINT_MAX, UINT_MAX };
322 char oldestKey[1024];
323 char currentKey[1024];
325 strcpy( rootKey, icvWindowPosRootKey );
326 rootKey[strlen(rootKey)-1] = '\0';
327 if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
328 //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
333 DWORD csize = sizeof(currentKey);
334 FILETIME accesstime = { 0, 0 };
335 LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
336 if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
339 if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
340 oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
341 oldestTime.dwLowDateTime > accesstime.dwLowDateTime )
343 oldestTime = accesstime;
344 strcpy( oldestKey, currentKey );
348 if( count >= MAX_RECORD_COUNT )
349 RegDeleteKey( hroot, oldestKey );
350 RegCloseKey( hroot );
352 if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
358 if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
362 RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x));
363 RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y));
364 RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width));
365 RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height));
370 CV_IMPL int cvNamedWindow( const char* name, int flags )
373 CV_FUNCNAME( "cvNamedWindow" );
379 DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
386 CV_ERROR( CV_StsNullPtr, "NULL name string" );
388 // Check the name in the storage
389 if( icvFindWindowByName( name ) != 0 )
395 if( (flags & CV_WINDOW_AUTOSIZE) == 0 )
396 defStyle |= WS_SIZEBOX;
398 icvLoadWindowPos( name, rect );
400 mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
401 rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
403 CV_ERROR( CV_StsError, "Frame window can not be created" );
405 ShowWindow(mainhWnd, SW_SHOW);
407 hWnd = CreateWindow("HighGUI class", "", defStyle | WS_CHILD | WS_SIZEBOX,
408 CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
410 CV_ERROR( CV_StsError, "Frame window can not be created" );
412 ShowWindow(hWnd, SW_SHOW);
414 len = (int)strlen(name);
415 CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
417 window->signature = CV_WINDOW_MAGIC_VAL;
419 window->frame = mainhWnd;
420 window->name = (char*)(window + 1);
421 memcpy( window->name, name, len + 1 );
422 window->flags = flags;
424 window->dc = CreateCompatibleDC(0);
425 window->last_key = 0;
427 window->on_mouse = 0;
428 window->on_mouse_param = 0;
430 memset( &window->toolbar, 0, sizeof(window->toolbar));
432 window->next = hg_windows;
435 hg_windows->prev = window;
437 icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
438 icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
440 // Recalculate window position
441 icvUpdateWindowPos( window );
450 static void icvRemoveWindow( CvWindow* window )
452 CvTrackbar* trackbar;
455 GetWindowRect( window->frame, &wrect );
456 icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
457 wrect.right-wrect.left, wrect.bottom-wrect.top) );
459 icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
460 icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
463 window->prev->next = window->next;
465 hg_windows = window->next;
468 window->next->prev = window->prev;
470 window->prev = window->next = 0;
473 DeleteObject(SelectObject(window->dc,window->image));
476 DeleteDC(window->dc);
478 for( trackbar = window->toolbar.first; trackbar != 0; )
480 CvTrackbar* next = trackbar->next;
481 icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
490 CV_IMPL void cvDestroyWindow( const char* name )
492 CV_FUNCNAME( "cvDestroyWindow" );
500 CV_ERROR( CV_StsNullPtr, "NULL name string" );
502 window = icvFindWindowByName( name );
506 mainhWnd = window->frame;
508 SendMessage(window->hwnd, WM_CLOSE, 0, 0);
509 SendMessage( mainhWnd, WM_CLOSE, 0, 0);
510 // Do NOT call _remove_window -- CvWindow list will be updated automatically ...
516 static void icvScreenToClient( HWND hwnd, RECT* rect )
521 ScreenToClient(hwnd, &p);
522 OffsetRect( rect, p.x - rect->left, p.y - rect->top );
526 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
527 static RECT icvCalcWindowRect( CvWindow* window )
529 const int gutter = 1;
530 RECT crect, trect, rect;
534 GetClientRect(window->frame, &crect);
535 if(window->toolbar.toolbar)
537 GetWindowRect(window->toolbar.toolbar, &trect);
538 icvScreenToClient(window->frame, &trect);
539 SubtractRect( &rect, &crect, &trect);
546 rect.bottom -= gutter;
547 rect.right -= gutter;
552 // returns TRUE if there is a problem such as ERROR_IO_PENDING.
553 static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
557 HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
559 size->cx = size->cy = 0;
565 if (GetObject(h, sizeof(bmp), &bmp) == 0)
570 size->cx = abs(bmp.bmWidth);
571 size->cy = abs(bmp.bmHeight);
575 *channels = bmp.bmBitsPixel/8;
584 static void icvUpdateWindowPos( CvWindow* window )
589 if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
593 icvGetBitmapData( window, &size, 0, 0 );
595 // Repeat two times because after the first resizing of the mainhWnd window
596 // toolbar may resize too
597 for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
599 RECT rmw, rw = icvCalcWindowRect(window );
600 MoveWindow(window->hwnd, rw.left, rw.top,
601 rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
602 GetClientRect(window->hwnd, &rw);
603 GetWindowRect(window->frame, &rmw);
604 // Resize the mainhWnd window in order to make the bitmap fit into the child window
605 MoveWindow(window->frame, rmw.left, rmw.top,
606 rmw.right - rmw.left + size.cx - rw.right + rw.left,
607 rmw.bottom - rmw.top + size.cy - rw.bottom + rw.top, TRUE );
611 rect = icvCalcWindowRect(window);
612 MoveWindow(window->hwnd, rect.left, rect.top,
613 rect.right - rect.left + 1,
614 rect.bottom - rect.top + 1, TRUE );
619 cvShowImage( const char* name, const CvArr* arr )
621 CV_FUNCNAME( "cvShowImage" );
626 SIZE size = { 0, 0 };
629 const int channels0 = 3;
631 CvMat stub, dst, *image;
632 bool changed_size = false; // philipg
635 CV_ERROR( CV_StsNullPtr, "NULL name" );
637 window = icvFindWindowByName(name);
638 if( !window || !arr )
639 EXIT; // keep silence here.
641 if( CV_IS_IMAGE_HDR( arr ))
642 origin = ((IplImage*)arr)->origin;
644 CV_CALL( image = cvGetMat( arr, &stub ));
647 // if there is something wrong with these system calls, we cannot display image...
648 if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
651 if( size.cx != image->width || size.cy != image->height || channels != channels0 )
655 uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
656 BITMAPINFO* binfo = (BITMAPINFO*)buffer;
658 DeleteObject( SelectObject( window->dc, window->image ));
661 size.cx = image->width;
662 size.cy = image->height;
663 channels = channels0;
665 FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
667 window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
668 DIB_RGB_COLORS, &dst_ptr, 0, 0));
671 cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3,
672 dst_ptr, (size.cx * channels + 3) & -4 );
673 cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
675 // ony resize window if needed
677 icvUpdateWindowPos(window);
678 InvalidateRect(window->hwnd, 0, 0);
679 // philipg: this is not needed and just slows things down
680 // UpdateWindow(window->hwnd);
686 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
688 CV_FUNCNAME( "cvResizeWindow" );
697 CV_ERROR( CV_StsNullPtr, "NULL name" );
699 window = icvFindWindowByName(name);
703 // Repeat two times because after the first resizing of the mainhWnd window
704 // toolbar may resize too
705 for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
707 rw = icvCalcWindowRect(window);
708 MoveWindow(window->hwnd, rw.left, rw.top,
709 rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
710 GetClientRect(window->hwnd, &rw);
711 GetWindowRect(window->frame, &rmw);
712 // Resize the mainhWnd window in order to make the bitmap fit into the child window
713 MoveWindow(window->frame, rmw.left, rmw.top,
714 rmw.right - rmw.left + width - rw.right + rw.left,
715 rmw.bottom - rmw.top + height - rw.bottom + rw.top, TRUE);
718 rect = icvCalcWindowRect(window);
719 MoveWindow(window->hwnd, rect.left, rect.top,
720 rect.right - rect.left + 1, rect.bottom - rect.top + 1, TRUE);
726 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
728 CV_FUNCNAME( "cvMoveWindow" );
736 CV_ERROR( CV_StsNullPtr, "NULL name" );
738 window = icvFindWindowByName(name);
742 GetWindowRect( window->frame, &rect );
743 MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
749 static LRESULT CALLBACK
750 MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
752 CvWindow* window = icvWindowByHWND( hwnd );
754 return DefWindowProc(hwnd, uMsg, wParam, lParam);
760 icvRemoveWindow(window);
762 //PostQuitMessage(0);
765 case WM_GETMINMAXINFO:
766 if( !(window->flags & CV_WINDOW_AUTOSIZE) )
768 MINMAXINFO* minmax = (MINMAXINFO*)lParam;
770 LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);
772 minmax->ptMinTrackSize.y = 100;
773 minmax->ptMinTrackSize.x = 100;
775 if( window->toolbar.first )
777 GetWindowRect( window->toolbar.first->hwnd, &rect );
778 minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
779 minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
785 case WM_WINDOWPOSCHANGED:
787 WINDOWPOS* pos = (WINDOWPOS*)lParam;
789 // Update the toolbar position/size
790 if(window->toolbar.toolbar)
793 GetWindowRect(window->toolbar.toolbar, &rect);
794 MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
797 if(!(window->flags & CV_WINDOW_AUTOSIZE))
798 icvUpdateWindowPos(window);
804 if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
805 SetFocus(window->hwnd);
811 HRGN rgn, rgn1, rgn2;
813 HDC hdc = (HDC)wParam;
814 GetWindowRect(window->hwnd, &cr);
815 icvScreenToClient(window->frame, &cr);
816 if(window->toolbar.toolbar)
818 GetWindowRect(window->toolbar.toolbar, &tr);
819 icvScreenToClient(window->frame, &tr);
822 tr.left = tr.top = tr.right = tr.bottom = 0;
824 GetClientRect(window->frame, &wrc);
826 rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
827 rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
828 rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom);
829 ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
830 ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
832 if(ret != NULLREGION && ret != ERROR)
833 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
842 return DefWindowProc(hwnd, uMsg, wParam, lParam);
846 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
848 CvWindow* window = icvWindowByHWND(hwnd);
850 // This window is not mentioned in HighGUI storage
851 // Actually, this should be error except for the case of calls to CreateWindow
852 return DefWindowProc(hwnd, uMsg, wParam, lParam);
854 // Process the message
857 case WM_WINDOWPOSCHANGING:
859 LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
860 RECT rect = icvCalcWindowRect(window);
863 pos->cx = rect.right - rect.left + 1;
864 pos->cy = rect.bottom - rect.top + 1;
871 case WM_LBUTTONDBLCLK:
872 case WM_RBUTTONDBLCLK:
873 case WM_MBUTTONDBLCLK:
878 if( window->on_mouse )
884 int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
885 (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
886 (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
887 (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
888 (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
889 (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
890 int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN :
891 uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN :
892 uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN :
893 uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP :
894 uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP :
895 uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP :
896 uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK :
897 uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
898 uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
900 if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
902 if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
905 pt.x = LOWORD( lParam );
906 pt.y = HIWORD( lParam );
908 GetClientRect( window->hwnd, &rect );
909 icvGetBitmapData( window, &size, 0, 0 );
911 window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
912 pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
913 window->on_mouse_param );
918 if(window->image != 0)
926 // Determine the bitmap's dimensions
927 icvGetBitmapData( window, &size, &nchannels, 0 );
929 hdc = BeginPaint(hwnd, &paint);
930 SetStretchBltMode(hdc, COLORONCOLOR);
935 for(i = 0; i < 256; i++)
937 table[i].rgbBlue = (unsigned char)i;
938 table[i].rgbGreen = (unsigned char)i;
939 table[i].rgbRed = (unsigned char)i;
941 SetDIBColorTable(window->dc, 0, 255, table);
944 if(window->flags & CV_WINDOW_AUTOSIZE)
946 BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
951 GetClientRect(window->hwnd, &rect);
952 StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
953 window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
956 EndPaint(hwnd, &paint);
960 return DefWindowProc(hwnd, uMsg, wParam, lParam);
971 icvRemoveWindow(window);
973 //PostQuitMessage(0);
977 SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
981 window->last_key = (int)wParam;
985 return DefWindowProc(hwnd, uMsg, wParam, lParam);
989 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
993 if( hg_on_preprocess )
995 int was_processed = 0;
996 int ret = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1000 ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
1002 if(hg_on_postprocess)
1004 int was_processed = 0;
1005 int ret = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1014 static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
1016 const int max_name_len = 10;
1017 const char* suffix = "";
1021 if( trackbar->data )
1022 *trackbar->data = pos;
1024 if( trackbar->pos != pos )
1026 trackbar->pos = pos;
1027 if( trackbar->notify )
1028 trackbar->notify(pos);
1030 name_len = (int)strlen(trackbar->name);
1032 if( name_len > max_name_len )
1034 int start_len = max_name_len*2/3;
1035 int end_len = max_name_len - start_len - 2;
1036 memcpy( pos_text, trackbar->name, start_len );
1037 memcpy( pos_text + start_len, "...", 3 );
1038 memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
1042 memcpy( pos_text, trackbar->name, name_len + 1);
1045 sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
1046 SetWindowText( trackbar->buddy, pos_text );
1051 static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1053 CvWindow* window = icvWindowByHWND( hwnd );
1055 return DefWindowProc(hwnd, uMsg, wParam, lParam);
1057 // Control messages processing
1060 // Slider processing
1063 HWND slider = (HWND)lParam;
1064 int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
1065 CvTrackbar* trackbar = icvTrackbarByHWND( slider );
1069 if( trackbar->pos != pos )
1070 icvUpdateTrackbar( trackbar, pos );
1073 SetFocus( window->hwnd );
1079 LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1080 int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
1082 if(window->toolbar.rows != rows)
1084 SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1085 CvTrackbar* trackbar = window->toolbar.first;
1087 for( ; trackbar != 0; trackbar = trackbar->next )
1090 SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
1091 (WPARAM)trackbar->id, (LPARAM)&rect);
1092 MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
1093 rect.right - rect.left - HG_BUDDY_WIDTH,
1094 rect.bottom - rect.top, FALSE);
1095 MoveWindow(trackbar->buddy, rect.left, rect.top,
1096 HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
1098 window->toolbar.rows = rows;
1104 return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1109 cvDestroyAllWindows(void)
1111 CvWindow* window = hg_windows;
1115 HWND mainhWnd = window->frame;
1116 HWND hwnd = window->hwnd;
1117 window = window->next;
1119 SendMessage( hwnd, WM_CLOSE, 0, 0 );
1120 SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
1126 cvWaitKey( int delay )
1128 int time0 = GetTickCount();
1134 int is_processed = 0;
1136 if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 )
1140 GetMessage(&message, 0, 0, 0);
1141 else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
1147 for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
1149 if( window->hwnd == message.hwnd || window->frame == message.hwnd )
1152 switch(message.message)
1156 DispatchMessage(&message);
1157 return (int)message.wParam;
1160 if( message.wParam == VK_F10 )
1163 return (int)(message.wParam << 16);
1168 TranslateMessage(&message);
1169 if( message.wParam >= VK_F1 && message.wParam <= VK_F24 ||
1170 message.wParam == VK_HOME || message.wParam == VK_END ||
1171 message.wParam == VK_UP || message.wParam == VK_DOWN ||
1172 message.wParam == VK_LEFT || message.wParam == VK_RIGHT ||
1173 message.wParam == VK_INSERT || message.wParam == VK_DELETE ||
1174 message.wParam == VK_PRIOR || message.wParam == VK_NEXT )
1176 DispatchMessage(&message);
1178 return (int)(message.wParam << 16);
1181 DispatchMessage(&message);
1190 TranslateMessage(&message);
1191 DispatchMessage(&message);
1198 icvFindTrackbarByName( const CvWindow* window, const char* name )
1200 CvTrackbar* trackbar = window->toolbar.first;
1202 for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
1226 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
1227 int* val, int count, CvTrackbarCallback on_notify )
1231 CV_FUNCNAME( "cvCreateTrackbar" );
1235 char slider_name[32];
1236 CvWindow* window = 0;
1237 CvTrackbar* trackbar = 0;
1240 if( !window_name || !trackbar_name )
1241 CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
1244 CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
1246 window = icvFindWindowByName(window_name);
1250 trackbar = icvFindTrackbarByName(window,trackbar_name);
1257 int len = (int)strlen( trackbar_name );
1259 // create toolbar if it is not created yet
1260 if( !window->toolbar.toolbar )
1262 const int default_height = 30;
1264 window->toolbar.toolbar = CreateToolbarEx(
1265 window->frame, WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE,
1266 1, 0, 0, 0, 0, 0, 16, 20, 16, 16, sizeof(TBBUTTON));
1267 GetClientRect(window->frame, &rect);
1268 MoveWindow( window->toolbar.toolbar, 0, 0,
1269 rect.right - rect.left, default_height, TRUE);
1270 SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
1271 ShowWindow(window->toolbar.toolbar, SW_SHOW);
1273 window->toolbar.first = 0;
1274 window->toolbar.pos = 0;
1275 window->toolbar.rows = 0;
1276 window->toolbar.toolBarProc =
1277 (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);
1279 icvUpdateWindowPos(window);
1281 // Subclassing from toolbar
1282 icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
1283 icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
1286 /* Retrieve current buttons count */
1287 bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1291 /* If this is not the first button then we need to
1292 separate it from the previous one */
1294 tbs.idCommand = bcount; // Set button id to it's number
1296 tbs.fsStyle = TBSTYLE_SEP;
1297 tbs.fsState = TBSTATE_ENABLED;
1298 SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
1300 // Retrieve current buttons count
1301 bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1304 /* Add a button which we're going to cover with the slider */
1306 tbs.idCommand = bcount; // Set button id to it's number
1307 tbs.fsState = TBSTATE_ENABLED;
1308 #if 0/*!defined WIN64 && !defined EM64T*/
1312 #ifndef TBSTYLE_AUTOSIZE
1313 #define TBSTYLE_AUTOSIZE 0x0010
1314 #define TBSTYLE_GROUP 0x0004
1316 //tbs.fsStyle = TBSTYLE_AUTOSIZE;
1317 tbs.fsStyle = TBSTYLE_GROUP;
1318 tbs.iString = (INT_PTR)trackbar_text;
1320 SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
1322 /* Adjust button size to the slider */
1323 tbis.cbSize = sizeof(tbis);
1324 tbis.dwMask = TBIF_SIZE;
1326 GetClientRect(window->hwnd, &rect);
1327 tbis.cx = (unsigned short)(rect.right - rect.left);
1329 SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
1330 (WPARAM)tbs.idCommand, (LPARAM)&tbis);
1332 /* Get button position */
1333 SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
1334 (WPARAM)tbs.idCommand, (LPARAM)&rect);
1336 /* Create a slider */
1337 trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
1338 trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
1339 trackbar->notify = 0;
1340 trackbar->parent = window;
1343 trackbar->id = bcount;
1344 trackbar->next = window->toolbar.first;
1345 trackbar->name = (char*)(trackbar + 1);
1346 memcpy( trackbar->name, trackbar_name, len + 1 );
1347 window->toolbar.first = trackbar;
1349 sprintf(slider_name, "Trackbar%p", val);
1350 trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
1351 WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
1352 TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
1353 rect.left + HG_BUDDY_WIDTH, rect.top,
1354 rect.right - rect.left - HG_BUDDY_WIDTH,
1355 rect.bottom - rect.top, window->toolbar.toolbar,
1356 (HMENU)(size_t)bcount, hg_hinstance, 0);
1358 sprintf(slider_name,"Buddy%p", val);
1359 trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
1360 WS_CHILD | SS_RIGHT,
1361 rect.left, rect.top,
1362 HG_BUDDY_WIDTH, rect.bottom - rect.top,
1363 window->toolbar.toolbar, 0, hg_hinstance, 0);
1365 icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
1367 /* Minimize the number of rows */
1368 SendMessage( window->toolbar.toolbar, TB_SETROWS,
1369 MAKEWPARAM(1, FALSE), (LPARAM)&rect );
1374 trackbar->notify = 0;
1377 trackbar->maxval = count;
1379 /* Adjust slider parameters */
1380 SendMessage(trackbar->hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, count));
1381 SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
1385 SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
1386 SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
1389 icvUpdateTrackbar( trackbar, pos );
1390 ShowWindow( trackbar->buddy, SW_SHOW );
1391 ShowWindow( trackbar->hwnd, SW_SHOW );
1393 trackbar->notify = on_notify;
1394 trackbar->data = val;
1396 /* Resize the window to reflect the toolbar resizing*/
1397 icvUpdateWindowPos(window);
1408 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
1410 CV_FUNCNAME( "cvSetMouseCallback" );
1414 CvWindow* window = 0;
1417 CV_ERROR( CV_StsNullPtr, "NULL window name" );
1419 window = icvFindWindowByName(window_name);
1423 window->on_mouse = on_mouse;
1424 window->on_mouse_param = param;
1430 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
1434 CV_FUNCNAME( "cvGetTrackbarPos" );
1439 CvTrackbar* trackbar = 0;
1441 if( trackbar_name == 0 || window_name == 0 )
1442 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1444 window = icvFindWindowByName( window_name );
1446 trackbar = icvFindTrackbarByName( window, trackbar_name );
1449 pos = trackbar->pos;
1457 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1459 CV_FUNCNAME( "cvSetTrackbarPos" );
1464 CvTrackbar* trackbar = 0;
1466 if( trackbar_name == 0 || window_name == 0 )
1467 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1469 window = icvFindWindowByName( window_name );
1471 trackbar = icvFindTrackbarByName( window, trackbar_name );
1478 if( pos > trackbar->maxval )
1479 pos = trackbar->maxval;
1481 SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
1482 icvUpdateTrackbar( trackbar, pos );
1489 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1493 CV_FUNCNAME( "cvGetWindowHandle" );
1499 if( window_name == 0 )
1500 CV_ERROR( CV_StsNullPtr, "NULL window name" );
1502 window = icvFindWindowByName( window_name );
1504 hwnd = (void*)window->hwnd;
1512 CV_IMPL const char* cvGetWindowName( void* window_handle )
1514 const char* window_name = "";
1516 CV_FUNCNAME( "cvGetWindowName" );
1522 if( window_handle == 0 )
1523 CV_ERROR( CV_StsNullPtr, "NULL window" );
1525 window = icvWindowByHWND( (HWND)window_handle );
1527 window_name = window->name;
1537 cvSetPreprocessFuncWin32(int (__cdecl *on_preprocess)(HWND, UINT, WPARAM, LPARAM, int*))
1540 hg_on_preprocess = on_preprocess;
1542 assert(on_preprocess);
1546 cvSetPostprocessFuncWin32(int (__cdecl *on_postprocess)(HWND, UINT, WPARAM, LPARAM, int*))
1549 hg_on_postprocess = on_postprocess;
1551 assert(on_postprocess);