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
FillBitmapInfo(BITMAPINFO * bmi,int width,int height,int bpp,int origin)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
icvCleanupHighgui()220 static void icvCleanupHighgui()
221 {
222 cvDestroyAllWindows();
223 UnregisterClass(highGUIclassName, hg_hinstance);
224 UnregisterClass(mainHighGUIclassName, hg_hinstance);
225 }
226
cvInitSystem(int,char **)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
cvStartWindowThread()268 CV_IMPL int cvStartWindowThread(){
269 return 0;
270 }
271
icvFindWindowByName(const char * name)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
icvWindowByHWND(HWND hwnd)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
icvTrackbarByHWND(HWND hwnd)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@cox.net">pgruebele@cox.net</a>
303 // Restores the window position from the registry saved position.
304 static void
icvLoadWindowPos(const char * name,CvRect & rect)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@cox.net">pgruebele@cox.net</a>
343 // philipg. Saves the window position in the registry
344 static void
icvSaveWindowPos(const char * name,CvRect rect)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
cvGetModeWindow_W32(const char * name)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
cvSetModeWindow_W32(const char * name,double prop_value)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
setWindowTitle(const String & winname,const String & title)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
cvGetPropWindowAutoSize_W32(const char * name)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
cvGetRatioWindow_W32(const char * name)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
cvGetOpenGlProp_W32(const char * name)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 {
createGlContext(HWND hWnd,HDC & hGLDC,HGLRC & hGLRC,bool & useGl)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
releaseGlContext(CvWindow * window)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
drawGl(CvWindow * window)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
resizeGl(CvWindow * window)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
cvNamedWindow(const char * name,int flags)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
cvSetOpenGlContext(const char * name)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
cvUpdateWindow(const char * name)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
cvSetOpenGlDrawCallback(const char * name,CvOpenGlDrawCallback callback,void * userdata)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
icvRemoveWindow(CvWindow * window)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
cvDestroyWindow(const char * name)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
icvScreenToClient(HWND hwnd,RECT * rect)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 */
icvCalcWindowRect(CvWindow * 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.
icvGetBitmapData(CvWindow * window,SIZE * size,int * channels,void ** data)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
icvUpdateWindowPos(CvWindow * window)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
cvShowImage(const char * name,const CvArr * arr)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
cvResizeWindow(const char * name,int width,int height)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
cvMoveWindow(const char * name,int x,int y)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
MainWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
HighGUIProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
icvUpdateTrackbar(CvTrackbar * trackbar,int pos)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
HGToolbarProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
cvDestroyAllWindows(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
showSaveDialog(CvWindow * window)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
cvWaitKey(int delay)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*
icvFindTrackbarByName(const CvWindow * window,const char * name)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
icvCreateTrackbar(const char * trackbar_name,const char * window_name,int * val,int count,CvTrackbarCallback on_notify,CvTrackbarCallback2 on_notify2,void * userdata)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
cvCreateTrackbar(const char * trackbar_name,const char * window_name,int * val,int count,CvTrackbarCallback on_notify)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
cvCreateTrackbar2(const char * trackbar_name,const char * window_name,int * val,int count,CvTrackbarCallback2 on_notify2,void * userdata)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
cvSetMouseCallback(const char * window_name,CvMouseCallback on_mouse,void * param)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
cvGetTrackbarPos(const char * trackbar_name,const char * window_name)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
cvSetTrackbarPos(const char * trackbar_name,const char * window_name,int pos)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
cvSetTrackbarMax(const char * trackbar_name,const char * window_name,int maxval)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
cvGetWindowHandle(const char * window_name)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
cvGetWindowName(void * window_handle)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
cvSetPreprocessFuncWin32_(const void * callback)2367 cvSetPreprocessFuncWin32_(const void* callback)
2368 {
2369 hg_on_preprocess = (CvWin32WindowCallback)callback;
2370 }
2371
2372 CV_IMPL void
cvSetPostprocessFuncWin32_(const void * callback)2373 cvSetPostprocessFuncWin32_(const void* callback)
2374 {
2375 hg_on_postprocess = (CvWin32WindowCallback)callback;
2376 }
2377
2378 #endif //WIN32
2379