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