Apply maemo2 patch
[opencv] / otherlibs / highgui / window_w32.cpp
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 "_highgui.h"
43
44 #if defined WIN32 || defined WIN64
45
46 #if _MSC_VER >= 1200
47 #pragma warning( disable: 4710 )
48 #endif
49
50 #include <commctrl.h>
51 #include <winuser.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <stdio.h>
55 #include <assert.h>
56
57 static const char* trackbar_text =
58 "                                                                                             ";
59
60 #if defined WIN64 || defined EM64T
61
62 #define icvGetWindowLongPtr GetWindowLongPtr
63 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
64 #define icvGetClassLongPtr  GetClassLongPtr
65
66 #define CV_USERDATA GWLP_USERDATA
67 #define CV_WNDPROC GWLP_WNDPROC
68 #define CV_HCURSOR GCLP_HCURSOR
69 #define CV_HBRBACKGROUND GCLP_HBRBACKGROUND
70
71 #else
72
73 #define icvGetWindowLongPtr GetWindowLong
74 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
75 #define icvGetClassLongPtr GetClassLong
76
77 #define CV_USERDATA GWL_USERDATA
78 #define CV_WNDPROC GWL_WNDPROC
79 #define CV_HCURSOR GCL_HCURSOR
80 #define CV_HBRBACKGROUND GCL_HBRBACKGROUND
81
82 #endif
83
84 void  FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
85 {
86     assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
87
88     BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
89
90     memset( bmih, 0, sizeof(*bmih));
91     bmih->biSize = sizeof(BITMAPINFOHEADER);
92     bmih->biWidth = width;
93     bmih->biHeight = origin ? abs(height) : -abs(height);
94     bmih->biPlanes = 1;
95     bmih->biBitCount = (unsigned short)bpp;
96     bmih->biCompression = BI_RGB;
97
98     if( bpp == 8 )
99     {
100         RGBQUAD* palette = bmi->bmiColors;
101         int i;
102         for( i = 0; i < 256; i++ )
103         {
104             palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
105             palette[i].rgbReserved = 0;
106         }
107     }
108 }
109
110 struct CvWindow;
111
112 typedef struct CvTrackbar
113 {
114     int signature;
115     HWND hwnd;
116     char* name;
117     CvTrackbar* next;
118     CvWindow* parent;
119     HWND buddy;
120     int* data;
121     int pos;
122     int maxval;
123     void (*notify)(int);
124     int id;
125 }
126 CvTrackbar;
127
128
129 typedef struct CvWindow
130 {
131     int signature;
132     HWND hwnd;
133     char* name;
134     CvWindow* prev;
135     CvWindow* next;
136     HWND frame;
137
138     HDC dc;
139     HGDIOBJ image;
140     int last_key;
141     int flags;
142
143     CvMouseCallback on_mouse;
144     void* on_mouse_param;
145
146     struct
147     {
148         HWND toolbar;
149         int pos;
150         int rows;
151         WNDPROC toolBarProc;
152         CvTrackbar* first;
153     }
154     toolbar;
155 }
156 CvWindow;
157
158
159 #define HG_BUDDY_WIDTH  130
160
161 #ifndef TBIF_SIZE
162     #define TBIF_SIZE  0x40
163 #endif
164
165 #ifndef TB_SETBUTTONINFO
166     #define TB_SETBUTTONINFO (WM_USER + 66)
167 #endif
168
169 #ifndef TBM_GETTOOLTIPS
170     #define TBM_GETTOOLTIPS  (WM_USER + 30)
171 #endif
172
173 static LRESULT CALLBACK HighGUIProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
174 static LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
175 static LRESULT CALLBACK MainWindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
176 static void icvUpdateWindowPos( CvWindow* window );
177
178 static CvWindow* hg_windows = 0;
179 static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
180 static HINSTANCE hg_hinstance = 0;
181
182 static const char* highGUIclassName = "HighGUI class";
183 static const char* mainHighGUIclassName = "Main HighGUI class";
184
185 static void icvCleanupHighgui()
186 {
187     cvDestroyAllWindows();
188     UnregisterClass(highGUIclassName, hg_hinstance);
189     UnregisterClass(mainHighGUIclassName, hg_hinstance);
190 }
191
192 CV_IMPL int cvInitSystem( int, char** )
193 {
194     static int wasInitialized = 0;
195
196     // check initialization status
197     if( !wasInitialized )
198     {
199         // Initialize the stogare
200         hg_windows = 0;
201
202         // Register the class
203         WNDCLASS wndc;
204         wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
205         wndc.lpfnWndProc = WindowProc;
206         wndc.cbClsExtra = 0;
207         wndc.cbWndExtra = 0;
208         wndc.hInstance = hg_hinstance;
209         wndc.lpszClassName = highGUIclassName;
210         wndc.lpszMenuName = highGUIclassName;
211         wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
212         wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
213         wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
214
215         RegisterClass(&wndc);
216
217         wndc.lpszClassName = mainHighGUIclassName;
218         wndc.lpszMenuName = mainHighGUIclassName;
219         wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
220         wndc.lpfnWndProc = MainWindowProc;
221
222         RegisterClass(&wndc);
223         atexit( icvCleanupHighgui );
224
225         wasInitialized = 1;
226     }
227
228     return 0;
229 }
230
231 CV_IMPL int cvStartWindowThread(){
232     return 0;
233 }
234
235 static CvWindow* icvFindWindowByName( const char* name )
236 {
237     CvWindow* window = hg_windows;
238
239     for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
240         ;
241
242     return window;
243 }
244
245
246 static CvWindow* icvWindowByHWND( HWND hwnd )
247 {
248     CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
249     return window != 0 && hg_windows != 0 &&
250            window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
251 }
252
253
254 static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
255 {
256     CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
257     return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
258            trackbar->hwnd == hwnd ? trackbar : 0;
259 }
260
261
262 static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
263
264 // Window positions saving/loading added by Philip Gruebele.
265 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
266 // Restores the window position from the registry saved position.
267 static void
268 icvLoadWindowPos( const char* name, CvRect& rect )
269 {
270     HKEY hkey;
271     char szKey[1024];
272     strcpy( szKey, icvWindowPosRootKey );
273     strcat( szKey, name );
274
275     rect.x = rect.y = CW_USEDEFAULT;
276     rect.width = rect.height = 320;
277
278     if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
279     {
280         // Yes we are installed.
281         DWORD dwType = 0;
282         DWORD dwSize = sizeof(int);
283
284         RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize);
285         RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize);
286         RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize);
287         RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize);
288
289         if( rect.x != (int)CW_USEDEFAULT && (rect.x < -200 || rect.x > 3000) )
290             rect.x = 100;
291         if( rect.y != (int)CW_USEDEFAULT && (rect.y < -200 || rect.y > 3000) )
292             rect.y = 100;
293
294         if( rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000) )
295             rect.width = 100;
296         if( rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000) )
297             rect.height = 100;
298
299         RegCloseKey(hkey);
300     }
301 }
302
303
304 // Window positions saving/loading added by Philip Gruebele.
305 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
306 // philipg.  Saves the window position in the registry
307 static void
308 icvSaveWindowPos( const char* name, CvRect rect )
309 {
310     static const DWORD MAX_RECORD_COUNT = 100;
311     HKEY hkey;
312     char szKey[1024];
313     char rootKey[1024];
314     strcpy( szKey, icvWindowPosRootKey );
315     strcat( szKey, name );
316     
317     if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
318     {
319         HKEY hroot;
320         DWORD count = 0;
321         FILETIME oldestTime = { UINT_MAX, UINT_MAX };
322         char oldestKey[1024];
323         char currentKey[1024];
324
325         strcpy( rootKey, icvWindowPosRootKey );
326         rootKey[strlen(rootKey)-1] = '\0';
327         if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
328             //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
329             return;
330
331         for(;;)
332         {
333             DWORD csize = sizeof(currentKey);
334             FILETIME accesstime = { 0, 0 };
335             LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
336             if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
337                 break;
338             count++;
339             if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
340                 oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
341                 oldestTime.dwLowDateTime > accesstime.dwLowDateTime )
342             {
343                 oldestTime = accesstime;
344                 strcpy( oldestKey, currentKey );
345             }
346         }
347
348         if( count >= MAX_RECORD_COUNT )
349             RegDeleteKey( hroot, oldestKey );
350         RegCloseKey( hroot );
351
352         if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
353             return;
354     }
355     else
356     {
357         RegCloseKey( hkey );
358         if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
359             return;
360     }
361     
362     RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x));
363     RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y));
364     RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width));
365     RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height));
366     RegCloseKey(hkey);
367 }
368
369
370 CV_IMPL int cvNamedWindow( const char* name, int flags )
371 {
372     int result = 0;
373     CV_FUNCNAME( "cvNamedWindow" );
374
375     __BEGIN__;
376
377     HWND hWnd, mainhWnd;
378     CvWindow* window;
379     DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
380     int len;
381     CvRect rect;
382
383     cvInitSystem(0,0);
384
385     if( !name )
386         CV_ERROR( CV_StsNullPtr, "NULL name string" );
387
388     // Check the name in the storage
389     if( icvFindWindowByName( name ) != 0 )
390     {
391         result = 1;
392         EXIT;
393     }
394
395     if( (flags & CV_WINDOW_AUTOSIZE) == 0 )
396         defStyle |= WS_SIZEBOX;
397
398     icvLoadWindowPos( name, rect );
399
400     mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
401                              rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
402     if( !mainhWnd )
403         CV_ERROR( CV_StsError, "Frame window can not be created" );
404
405     ShowWindow(mainhWnd, SW_SHOW);
406
407     hWnd = CreateWindow("HighGUI class", "", defStyle | WS_CHILD | WS_SIZEBOX,
408                         CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
409     if( !hWnd )
410         CV_ERROR( CV_StsError, "Frame window can not be created" );
411
412     ShowWindow(hWnd, SW_SHOW);
413
414     len = (int)strlen(name);
415     CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
416
417     window->signature = CV_WINDOW_MAGIC_VAL;
418     window->hwnd = hWnd;
419     window->frame = mainhWnd;
420     window->name = (char*)(window + 1);
421     memcpy( window->name, name, len + 1 );
422     window->flags = flags;
423     window->image = 0;
424     window->dc = CreateCompatibleDC(0);
425     window->last_key = 0;
426
427     window->on_mouse = 0;
428     window->on_mouse_param = 0;
429
430     memset( &window->toolbar, 0, sizeof(window->toolbar));
431
432     window->next = hg_windows;
433     window->prev = 0;
434     if( hg_windows )
435         hg_windows->prev = window;
436     hg_windows = window;
437     icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
438     icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
439
440     // Recalculate window position
441     icvUpdateWindowPos( window );
442
443     result = 1;
444     __END__;
445
446     return result;
447 }
448
449
450 static void icvRemoveWindow( CvWindow* window )
451 {
452     CvTrackbar* trackbar;
453     RECT wrect;
454
455     GetWindowRect( window->frame, &wrect );
456     icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
457         wrect.right-wrect.left, wrect.bottom-wrect.top) );
458
459     icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
460     icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
461
462     if( window->prev )
463         window->prev->next = window->next;
464     else
465         hg_windows = window->next;
466
467     if( window->next )
468         window->next->prev = window->prev;
469
470     window->prev = window->next = 0;
471
472     if( window->image )
473         DeleteObject(SelectObject(window->dc,window->image));
474
475     if( window->dc )
476         DeleteDC(window->dc);
477
478     for( trackbar = window->toolbar.first; trackbar != 0; )
479     {
480         CvTrackbar* next = trackbar->next;
481         icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
482         cvFree( &trackbar );
483         trackbar = next;
484     }
485
486     cvFree( &window );
487 }
488
489
490 CV_IMPL void cvDestroyWindow( const char* name )
491 {
492     CV_FUNCNAME( "cvDestroyWindow" );
493
494     __BEGIN__;
495
496     CvWindow* window;
497     HWND mainhWnd;
498
499     if(!name)
500         CV_ERROR( CV_StsNullPtr, "NULL name string" );
501
502     window = icvFindWindowByName( name );
503     if( !window )
504         EXIT;
505
506     mainhWnd = window->frame;
507
508     SendMessage(window->hwnd, WM_CLOSE, 0, 0);
509     SendMessage( mainhWnd, WM_CLOSE, 0, 0);
510     // Do NOT call _remove_window -- CvWindow list will be updated automatically ...
511
512     __END__;
513 }
514
515
516 static void icvScreenToClient( HWND hwnd, RECT* rect )
517 {
518     POINT p;
519     p.x = rect->left;
520     p.y = rect->top;
521     ScreenToClient(hwnd, &p);
522     OffsetRect( rect, p.x - rect->left, p.y - rect->top );
523 }
524
525
526 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
527 static RECT icvCalcWindowRect( CvWindow* window )
528 {
529     const int gutter = 1;
530     RECT crect, trect, rect;
531
532     assert(window);
533
534     GetClientRect(window->frame, &crect);
535     if(window->toolbar.toolbar)
536     {
537         GetWindowRect(window->toolbar.toolbar, &trect);
538         icvScreenToClient(window->frame, &trect);
539         SubtractRect( &rect, &crect, &trect);
540     }
541     else
542         rect = crect;
543
544     rect.top += gutter;
545     rect.left += gutter;
546     rect.bottom -= gutter;
547     rect.right -= gutter;
548
549     return rect;
550 }
551
552 // returns TRUE if there is a problem such as ERROR_IO_PENDING.
553 static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
554 {
555     BITMAP bmp;
556     GdiFlush();
557     HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
558     if( size )
559         size->cx = size->cy = 0;
560     if( data )
561         *data = 0;
562
563     if (h == NULL)
564         return true;
565     if (GetObject(h, sizeof(bmp), &bmp) == 0)
566         return true;
567
568     if( size )
569     {
570         size->cx = abs(bmp.bmWidth);
571         size->cy = abs(bmp.bmHeight);
572     }
573
574     if( channels )
575         *channels = bmp.bmBitsPixel/8;
576
577     if( data )
578         *data = bmp.bmBits;
579
580     return false;
581 }
582
583
584 static void icvUpdateWindowPos( CvWindow* window )
585 {
586     RECT rect;
587     assert(window);
588
589     if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
590     {
591         int i;
592         SIZE size = {0,0};
593         icvGetBitmapData( window, &size, 0, 0 );
594
595         // Repeat two times because after the first resizing of the mainhWnd window
596         // toolbar may resize too
597         for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
598         {
599             RECT rmw, rw = icvCalcWindowRect(window );
600             MoveWindow(window->hwnd, rw.left, rw.top,
601                 rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
602             GetClientRect(window->hwnd, &rw);
603             GetWindowRect(window->frame, &rmw);
604             // Resize the mainhWnd window in order to make the bitmap fit into the child window
605             MoveWindow(window->frame, rmw.left, rmw.top,
606                 rmw.right - rmw.left + size.cx - rw.right + rw.left,
607                 rmw.bottom  - rmw.top + size.cy - rw.bottom + rw.top, TRUE );
608         }
609     }
610
611     rect = icvCalcWindowRect(window);
612     MoveWindow(window->hwnd, rect.left, rect.top,
613                rect.right - rect.left + 1,
614                rect.bottom - rect.top + 1, TRUE );
615 }
616
617
618 CV_IMPL void
619 cvShowImage( const char* name, const CvArr* arr )
620 {
621     CV_FUNCNAME( "cvShowImage" );
622
623     __BEGIN__;
624
625     CvWindow* window;
626     SIZE size = { 0, 0 };
627     int channels = 0;
628     void* dst_ptr = 0;
629     const int channels0 = 3;
630     int origin = 0;
631     CvMat stub, dst, *image;
632     bool changed_size = false; // philipg
633
634     if( !name )
635         CV_ERROR( CV_StsNullPtr, "NULL name" );
636
637     window = icvFindWindowByName(name);
638     if( !window || !arr )
639         EXIT; // keep silence here.
640
641     if( CV_IS_IMAGE_HDR( arr ))
642         origin = ((IplImage*)arr)->origin;
643
644     CV_CALL( image = cvGetMat( arr, &stub ));
645
646     if (window->image)
647         // if there is something wrong with these system calls, we cannot display image...
648         if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
649             return;
650
651     if( size.cx != image->width || size.cy != image->height || channels != channels0 )
652     {
653         changed_size = true;
654
655         uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
656         BITMAPINFO* binfo = (BITMAPINFO*)buffer;
657
658         DeleteObject( SelectObject( window->dc, window->image ));
659         window->image = 0;
660
661         size.cx = image->width;
662         size.cy = image->height;
663         channels = channels0;
664
665         FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
666
667         window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
668                                       DIB_RGB_COLORS, &dst_ptr, 0, 0));
669     }
670
671     cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3,
672                      dst_ptr, (size.cx * channels + 3) & -4 );
673     cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
674
675     // ony resize window if needed
676     if (changed_size)
677         icvUpdateWindowPos(window);
678     InvalidateRect(window->hwnd, 0, 0);
679     // philipg: this is not needed and just slows things down
680 //    UpdateWindow(window->hwnd);
681
682     __END__;
683 }
684
685
686 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
687 {
688     CV_FUNCNAME( "cvResizeWindow" );
689
690     __BEGIN__;
691
692     int i;
693     CvWindow* window;
694     RECT rmw, rw, rect;
695
696     if( !name )
697         CV_ERROR( CV_StsNullPtr, "NULL name" );
698
699     window = icvFindWindowByName(name);
700     if(!window)
701         EXIT;
702
703     // Repeat two times because after the first resizing of the mainhWnd window
704     // toolbar may resize too
705     for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
706     {
707         rw = icvCalcWindowRect(window);
708         MoveWindow(window->hwnd, rw.left, rw.top,
709             rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
710         GetClientRect(window->hwnd, &rw);
711         GetWindowRect(window->frame, &rmw);
712         // Resize the mainhWnd window in order to make the bitmap fit into the child window
713         MoveWindow(window->frame, rmw.left, rmw.top,
714             rmw.right - rmw.left + width - rw.right + rw.left,
715             rmw.bottom  - rmw.top + height - rw.bottom + rw.top, TRUE);
716     }
717
718     rect = icvCalcWindowRect(window);
719     MoveWindow(window->hwnd, rect.left, rect.top,
720         rect.right - rect.left + 1, rect.bottom - rect.top + 1, TRUE);
721
722     __END__;
723 }
724
725
726 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
727 {
728     CV_FUNCNAME( "cvMoveWindow" );
729
730     __BEGIN__;
731
732     CvWindow* window;
733     RECT rect;
734
735     if( !name )
736         CV_ERROR( CV_StsNullPtr, "NULL name" );
737
738     window = icvFindWindowByName(name);
739     if(!window)
740         EXIT;
741
742     GetWindowRect( window->frame, &rect );
743     MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
744
745     __END__;
746 }
747
748
749 static LRESULT CALLBACK
750 MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
751 {
752     CvWindow* window = icvWindowByHWND( hwnd );
753     if( !window )
754         return DefWindowProc(hwnd, uMsg, wParam, lParam);
755
756     switch(uMsg)
757     {
758     case WM_DESTROY:
759
760         icvRemoveWindow(window);
761         // Do nothing!!!
762         //PostQuitMessage(0);
763         break;
764
765     case WM_GETMINMAXINFO:
766         if( !(window->flags & CV_WINDOW_AUTOSIZE) )
767         {
768             MINMAXINFO* minmax = (MINMAXINFO*)lParam;
769             RECT rect;
770             LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);
771
772             minmax->ptMinTrackSize.y = 100;
773             minmax->ptMinTrackSize.x = 100;
774
775             if( window->toolbar.first )
776             {
777                 GetWindowRect( window->toolbar.first->hwnd, &rect );
778                 minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
779                 minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
780             }
781             return retval;
782         }
783         break;
784
785     case WM_WINDOWPOSCHANGED:
786         {
787             WINDOWPOS* pos = (WINDOWPOS*)lParam;
788
789             // Update the toolbar position/size
790             if(window->toolbar.toolbar)
791             {
792                 RECT rect;
793                 GetWindowRect(window->toolbar.toolbar, &rect);
794                 MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
795             }
796
797             if(!(window->flags & CV_WINDOW_AUTOSIZE))
798                 icvUpdateWindowPos(window);
799
800             break;
801         }
802
803     case WM_ACTIVATE:
804         if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
805             SetFocus(window->hwnd);
806         break;
807
808     case WM_ERASEBKGND:
809         {
810             RECT cr, tr, wrc;
811             HRGN rgn, rgn1, rgn2;
812             int ret;
813             HDC hdc = (HDC)wParam;
814             GetWindowRect(window->hwnd, &cr);
815             icvScreenToClient(window->frame, &cr);
816             if(window->toolbar.toolbar)
817             {
818                 GetWindowRect(window->toolbar.toolbar, &tr);
819                 icvScreenToClient(window->frame, &tr);
820             }
821             else
822                 tr.left = tr.top = tr.right = tr.bottom = 0;
823
824             GetClientRect(window->frame, &wrc);
825
826             rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
827             rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
828             rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom);
829             ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
830             ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
831
832             if(ret != NULLREGION && ret != ERROR)
833                 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
834
835             DeleteObject(rgn);
836             DeleteObject(rgn1);
837             DeleteObject(rgn2);
838         }
839         return 1;
840     }
841
842     return DefWindowProc(hwnd, uMsg, wParam, lParam);
843 }
844
845
846 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
847 {
848     CvWindow* window = icvWindowByHWND(hwnd);
849     if( !window )
850         // This window is not mentioned in HighGUI storage
851         // Actually, this should be error except for the case of calls to CreateWindow
852         return DefWindowProc(hwnd, uMsg, wParam, lParam);
853
854     // Process the message
855     switch(uMsg)
856     {
857     case WM_WINDOWPOSCHANGING:
858         {
859             LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
860             RECT rect = icvCalcWindowRect(window);
861             pos->x = rect.left;
862             pos->y = rect.top;
863             pos->cx = rect.right - rect.left + 1;
864             pos->cy = rect.bottom - rect.top + 1;
865         }
866         break;
867
868     case WM_LBUTTONDOWN:
869     case WM_RBUTTONDOWN:
870     case WM_MBUTTONDOWN:
871     case WM_LBUTTONDBLCLK:
872     case WM_RBUTTONDBLCLK:
873     case WM_MBUTTONDBLCLK:
874     case WM_LBUTTONUP:
875     case WM_RBUTTONUP:
876     case WM_MBUTTONUP:
877     case WM_MOUSEMOVE:
878         if( window->on_mouse )
879         {
880             POINT pt;
881             RECT rect;
882             SIZE size = {0,0};
883
884             int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
885                         (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
886                         (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
887                         (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
888                         (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
889                         (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
890             int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN :
891                         uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN :
892                         uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN :
893                         uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP :
894                         uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP :
895                         uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP :
896                         uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK :
897                         uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
898                         uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
899                                                    CV_EVENT_MOUSEMOVE;
900             if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
901                 SetCapture( hwnd );
902             if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
903                 ReleaseCapture();
904
905             pt.x = LOWORD( lParam );
906             pt.y = HIWORD( lParam );
907
908             GetClientRect( window->hwnd, &rect );
909             icvGetBitmapData( window, &size, 0, 0 );
910
911             window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
912                                      pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
913                                      window->on_mouse_param );
914         }
915         break;
916
917     case WM_PAINT:
918         if(window->image != 0)
919         {
920             int nchannels = 3;
921             SIZE size = {0,0};
922             PAINTSTRUCT paint;
923             HDC hdc;
924             RGBQUAD table[256];
925
926             // Determine the bitmap's dimensions
927             icvGetBitmapData( window, &size, &nchannels, 0 );
928
929             hdc = BeginPaint(hwnd, &paint);
930             SetStretchBltMode(hdc, COLORONCOLOR);
931
932             if( nchannels == 1 )
933             {
934                 int i;
935                 for(i = 0; i < 256; i++)
936                 {
937                     table[i].rgbBlue = (unsigned char)i;
938                     table[i].rgbGreen = (unsigned char)i;
939                     table[i].rgbRed = (unsigned char)i;
940                 }
941                 SetDIBColorTable(window->dc, 0, 255, table);
942             }
943
944             if(window->flags & CV_WINDOW_AUTOSIZE)
945             {
946                 BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
947             }
948             else
949             {
950                 RECT rect;
951                 GetClientRect(window->hwnd, &rect);
952                 StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
953                             window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
954             }
955             //DeleteDC(hdc);
956             EndPaint(hwnd, &paint);
957         }
958         else
959         {
960             return DefWindowProc(hwnd, uMsg, wParam, lParam);
961         }
962         return 0;
963
964     case WM_ERASEBKGND:
965         if(window->image)
966             return 0;
967         break;
968
969     case WM_DESTROY:
970
971         icvRemoveWindow(window);
972         // Do nothing!!!
973         //PostQuitMessage(0);
974         break;
975
976     case WM_SETCURSOR:
977         SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
978         return 0;
979
980     case WM_KEYDOWN:
981         window->last_key = (int)wParam;
982         return 0;
983     }
984
985     return DefWindowProc(hwnd, uMsg, wParam, lParam);
986 }
987
988
989 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
990 {
991     LRESULT ret;
992
993     if( hg_on_preprocess )
994     {
995         int was_processed = 0;
996         int ret = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
997         if( was_processed )
998             return ret;
999     }
1000     ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
1001
1002     if(hg_on_postprocess)
1003     {
1004         int was_processed = 0;
1005         int ret = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
1006         if( was_processed )
1007             return ret;
1008     }
1009
1010     return ret;
1011 }
1012
1013
1014 static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
1015 {
1016     const int max_name_len = 10;
1017     const char* suffix = "";
1018     char pos_text[32];
1019     int name_len;
1020
1021     if( trackbar->data )
1022         *trackbar->data = pos;
1023
1024     if( trackbar->pos != pos )
1025     {
1026         trackbar->pos = pos;
1027         if( trackbar->notify )
1028             trackbar->notify(pos);
1029
1030         name_len = (int)strlen(trackbar->name);
1031
1032         if( name_len > max_name_len )
1033         {
1034             int start_len = max_name_len*2/3;
1035             int end_len = max_name_len - start_len - 2;
1036             memcpy( pos_text, trackbar->name, start_len );
1037             memcpy( pos_text + start_len, "...", 3 );
1038             memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
1039         }
1040         else
1041         {
1042             memcpy( pos_text, trackbar->name, name_len + 1);
1043         }
1044
1045         sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
1046         SetWindowText( trackbar->buddy, pos_text );
1047     }
1048 }
1049
1050
1051 static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1052 {
1053     CvWindow* window = icvWindowByHWND( hwnd );
1054     if(!window)
1055         return DefWindowProc(hwnd, uMsg, wParam, lParam);
1056
1057     // Control messages processing
1058     switch(uMsg)
1059     {
1060     // Slider processing
1061     case WM_HSCROLL:
1062         {
1063             HWND slider = (HWND)lParam;
1064             int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
1065             CvTrackbar* trackbar = icvTrackbarByHWND( slider );
1066
1067             if( trackbar )
1068             {
1069                 if( trackbar->pos != pos )
1070                     icvUpdateTrackbar( trackbar, pos );
1071             }
1072
1073             SetFocus( window->hwnd );
1074             return 0;
1075         }
1076
1077     case WM_NCCALCSIZE:
1078         {
1079             LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1080             int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
1081
1082             if(window->toolbar.rows != rows)
1083             {
1084                 SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1085                 CvTrackbar* trackbar = window->toolbar.first;
1086
1087                 for( ; trackbar != 0; trackbar = trackbar->next )
1088                 {
1089                     RECT rect;
1090                     SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
1091                                (WPARAM)trackbar->id, (LPARAM)&rect);
1092                     MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
1093                                rect.right - rect.left - HG_BUDDY_WIDTH,
1094                                rect.bottom - rect.top, FALSE);
1095                     MoveWindow(trackbar->buddy, rect.left, rect.top,
1096                                HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
1097                 }
1098                 window->toolbar.rows = rows;
1099             }
1100             return ret;
1101         }
1102     }
1103
1104     return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
1105 }
1106
1107
1108 CV_IMPL void
1109 cvDestroyAllWindows(void)
1110 {
1111     CvWindow* window = hg_windows;
1112
1113     while( window )
1114     {
1115         HWND mainhWnd = window->frame;
1116         HWND hwnd = window->hwnd;
1117         window = window->next;
1118
1119         SendMessage( hwnd, WM_CLOSE, 0, 0 );
1120         SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
1121     }
1122 }
1123
1124
1125 CV_IMPL int
1126 cvWaitKey( int delay )
1127 {
1128     int time0 = GetTickCount();
1129
1130     for(;;)
1131     {
1132         CvWindow* window;
1133         MSG message;
1134         int is_processed = 0;
1135
1136         if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 )
1137             return -1;
1138
1139         if( delay <= 0 )
1140             GetMessage(&message, 0, 0, 0);
1141         else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
1142         {
1143             Sleep(1);
1144             continue;
1145         }
1146
1147         for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
1148         {
1149             if( window->hwnd == message.hwnd || window->frame == message.hwnd )
1150             {
1151                 is_processed = 1;
1152                 switch(message.message)
1153                 {
1154                 case WM_DESTROY:
1155                 case WM_CHAR:
1156                     DispatchMessage(&message);
1157                     return (int)message.wParam;
1158
1159                 case WM_SYSKEYDOWN:
1160                     if( message.wParam == VK_F10 )
1161                     {
1162                         is_processed = 1;
1163                         return (int)(message.wParam << 16);
1164                     }
1165                     break;
1166
1167                 case WM_KEYDOWN:
1168                     TranslateMessage(&message);
1169                     if( message.wParam >= VK_F1 && message.wParam <= VK_F24 ||
1170                         message.wParam == VK_HOME || message.wParam == VK_END ||
1171                         message.wParam == VK_UP || message.wParam == VK_DOWN ||
1172                         message.wParam == VK_LEFT || message.wParam == VK_RIGHT ||
1173                         message.wParam == VK_INSERT || message.wParam == VK_DELETE ||
1174                         message.wParam == VK_PRIOR || message.wParam == VK_NEXT )
1175                     {
1176                         DispatchMessage(&message);
1177                         is_processed = 1;
1178                         return (int)(message.wParam << 16);
1179                     }
1180                 default:
1181                     DispatchMessage(&message);
1182                     is_processed = 1;
1183                     break;
1184                 }
1185             }
1186         }
1187
1188         if( !is_processed )
1189         {
1190             TranslateMessage(&message);
1191             DispatchMessage(&message);
1192         }
1193     }
1194 }
1195
1196
1197 static CvTrackbar*
1198 icvFindTrackbarByName( const CvWindow* window, const char* name )
1199 {
1200     CvTrackbar* trackbar = window->toolbar.first;
1201
1202     for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
1203         ;
1204
1205     return trackbar;
1206 }
1207
1208
1209 typedef struct
1210 {
1211     UINT cbSize;
1212     DWORD dwMask;
1213     int idCommand;
1214     int iImage;
1215     BYTE fsState;
1216     BYTE fsStyle;
1217     WORD cx;
1218     DWORD lParam;
1219     LPSTR pszText;
1220     int cchText;
1221 }
1222 ButtonInfo;
1223
1224
1225 CV_IMPL int
1226 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
1227                   int* val, int count, CvTrackbarCallback on_notify )
1228 {
1229     int result = 0;
1230
1231     CV_FUNCNAME( "cvCreateTrackbar" );
1232
1233     __BEGIN__;
1234
1235     char slider_name[32];
1236     CvWindow* window = 0;
1237     CvTrackbar* trackbar = 0;
1238     int pos = 0;
1239
1240     if( !window_name || !trackbar_name )
1241         CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
1242
1243     if( count <= 0 )
1244         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
1245
1246     window = icvFindWindowByName(window_name);
1247     if( !window )
1248         EXIT;
1249
1250     trackbar = icvFindTrackbarByName(window,trackbar_name);
1251     if( !trackbar )
1252     {
1253         TBBUTTON tbs;
1254         ButtonInfo tbis;
1255         RECT rect;
1256         int bcount;
1257         int len = (int)strlen( trackbar_name );
1258
1259         // create toolbar if it is not created yet
1260         if( !window->toolbar.toolbar )
1261         {
1262             const int default_height = 30;
1263
1264             window->toolbar.toolbar = CreateToolbarEx(
1265                     window->frame, WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE,
1266                     1, 0, 0, 0, 0, 0, 16, 20, 16, 16, sizeof(TBBUTTON));
1267             GetClientRect(window->frame, &rect);
1268             MoveWindow( window->toolbar.toolbar, 0, 0,
1269                         rect.right - rect.left, default_height, TRUE);
1270             SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
1271             ShowWindow(window->toolbar.toolbar, SW_SHOW);
1272
1273             window->toolbar.first = 0;
1274             window->toolbar.pos = 0;
1275             window->toolbar.rows = 0;
1276             window->toolbar.toolBarProc =
1277                 (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);
1278
1279             icvUpdateWindowPos(window);
1280
1281             // Subclassing from toolbar
1282             icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
1283             icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
1284         }
1285
1286         /* Retrieve current buttons count */
1287         bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1288
1289         if(bcount > 1)
1290         {
1291             /* If this is not the first button then we need to
1292             separate it from the previous one */
1293             tbs.iBitmap = 0;
1294             tbs.idCommand = bcount; // Set button id to it's number
1295             tbs.iString = 0;
1296             tbs.fsStyle = TBSTYLE_SEP;
1297             tbs.fsState = TBSTATE_ENABLED;
1298             SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
1299
1300             // Retrieve current buttons count
1301             bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
1302         }
1303
1304         /* Add a button which we're going to cover with the slider */
1305         tbs.iBitmap = 0;
1306         tbs.idCommand = bcount; // Set button id to it's number
1307         tbs.fsState = TBSTATE_ENABLED;
1308 #if 0/*!defined WIN64 && !defined EM64T*/
1309         tbs.fsStyle = 0;
1310         tbs.iString = 0;
1311 #else
1312 #ifndef TBSTYLE_AUTOSIZE
1313 #define TBSTYLE_AUTOSIZE        0x0010
1314 #define TBSTYLE_GROUP           0x0004
1315 #endif
1316         //tbs.fsStyle = TBSTYLE_AUTOSIZE;
1317         tbs.fsStyle = TBSTYLE_GROUP;
1318         tbs.iString = (INT_PTR)trackbar_text;
1319 #endif
1320         SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
1321
1322         /* Adjust button size to the slider */
1323         tbis.cbSize = sizeof(tbis);
1324         tbis.dwMask = TBIF_SIZE;
1325
1326         GetClientRect(window->hwnd, &rect);
1327         tbis.cx = (unsigned short)(rect.right - rect.left);
1328
1329         SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
1330             (WPARAM)tbs.idCommand, (LPARAM)&tbis);
1331
1332         /* Get button position */
1333         SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
1334             (WPARAM)tbs.idCommand, (LPARAM)&rect);
1335
1336         /* Create a slider */
1337         trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
1338         trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
1339         trackbar->notify = 0;
1340         trackbar->parent = window;
1341         trackbar->pos = 0;
1342         trackbar->data = 0;
1343         trackbar->id = bcount;
1344         trackbar->next = window->toolbar.first;
1345         trackbar->name = (char*)(trackbar + 1);
1346         memcpy( trackbar->name, trackbar_name, len + 1 );
1347         window->toolbar.first = trackbar;
1348
1349         sprintf(slider_name, "Trackbar%p", val);
1350         trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
1351                             WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
1352                             TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
1353                             rect.left + HG_BUDDY_WIDTH, rect.top,
1354                             rect.right - rect.left - HG_BUDDY_WIDTH,
1355                             rect.bottom - rect.top, window->toolbar.toolbar,
1356                             (HMENU)(size_t)bcount, hg_hinstance, 0);
1357
1358         sprintf(slider_name,"Buddy%p", val);
1359         trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
1360                             WS_CHILD | SS_RIGHT,
1361                             rect.left, rect.top,
1362                             HG_BUDDY_WIDTH, rect.bottom - rect.top,
1363                             window->toolbar.toolbar, 0, hg_hinstance, 0);
1364
1365         icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
1366
1367         /* Minimize the number of rows */
1368         SendMessage( window->toolbar.toolbar, TB_SETROWS,
1369                      MAKEWPARAM(1, FALSE), (LPARAM)&rect );
1370     }
1371     else
1372     {
1373         trackbar->data = 0;
1374         trackbar->notify = 0;
1375     }
1376
1377     trackbar->maxval = count;
1378
1379     /* Adjust slider parameters */
1380     SendMessage(trackbar->hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, count));
1381     SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
1382     if( val )
1383         pos = *val;
1384
1385     SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
1386     SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
1387
1388     trackbar->pos = -1;
1389     icvUpdateTrackbar( trackbar, pos );
1390     ShowWindow( trackbar->buddy, SW_SHOW );
1391     ShowWindow( trackbar->hwnd, SW_SHOW );
1392
1393     trackbar->notify = on_notify;
1394     trackbar->data = val;
1395
1396     /* Resize the window to reflect the toolbar resizing*/
1397     icvUpdateWindowPos(window);
1398
1399     result = 1;
1400
1401     __END__;
1402
1403     return result;
1404 }
1405
1406
1407 CV_IMPL void
1408 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
1409 {
1410     CV_FUNCNAME( "cvSetMouseCallback" );
1411
1412     __BEGIN__;
1413
1414     CvWindow* window = 0;
1415
1416     if( !window_name )
1417         CV_ERROR( CV_StsNullPtr, "NULL window name" );
1418
1419     window = icvFindWindowByName(window_name);
1420     if( !window )
1421         EXIT;
1422
1423     window->on_mouse = on_mouse;
1424     window->on_mouse_param = param;
1425
1426     __END__;
1427 }
1428
1429
1430 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
1431 {
1432     int pos = -1;
1433
1434     CV_FUNCNAME( "cvGetTrackbarPos" );
1435
1436     __BEGIN__;
1437
1438     CvWindow* window;
1439     CvTrackbar* trackbar = 0;
1440
1441     if( trackbar_name == 0 || window_name == 0 )
1442         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1443
1444     window = icvFindWindowByName( window_name );
1445     if( window )
1446         trackbar = icvFindTrackbarByName( window, trackbar_name );
1447
1448     if( trackbar )
1449         pos = trackbar->pos;
1450
1451     __END__;
1452
1453     return pos;
1454 }
1455
1456
1457 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1458 {
1459     CV_FUNCNAME( "cvSetTrackbarPos" );
1460
1461     __BEGIN__;
1462
1463     CvWindow* window;
1464     CvTrackbar* trackbar = 0;
1465
1466     if( trackbar_name == 0 || window_name == 0 )
1467         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1468
1469     window = icvFindWindowByName( window_name );
1470     if( window )
1471         trackbar = icvFindTrackbarByName( window, trackbar_name );
1472
1473     if( trackbar )
1474     {
1475         if( pos < 0 )
1476             pos = 0;
1477
1478         if( pos > trackbar->maxval )
1479             pos = trackbar->maxval;
1480
1481         SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
1482         icvUpdateTrackbar( trackbar, pos );
1483     }
1484
1485     __END__;
1486 }
1487
1488
1489 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1490 {
1491     void* hwnd = 0;
1492
1493     CV_FUNCNAME( "cvGetWindowHandle" );
1494
1495     __BEGIN__;
1496
1497     CvWindow* window;
1498
1499     if( window_name == 0 )
1500         CV_ERROR( CV_StsNullPtr, "NULL window name" );
1501
1502     window = icvFindWindowByName( window_name );
1503     if( window )
1504         hwnd = (void*)window->hwnd;
1505
1506     __END__;
1507
1508     return hwnd;
1509 }
1510
1511
1512 CV_IMPL const char* cvGetWindowName( void* window_handle )
1513 {
1514     const char* window_name = "";
1515
1516     CV_FUNCNAME( "cvGetWindowName" );
1517
1518     __BEGIN__;
1519
1520     CvWindow* window;
1521
1522     if( window_handle == 0 )
1523         CV_ERROR( CV_StsNullPtr, "NULL window" );
1524
1525     window = icvWindowByHWND( (HWND)window_handle );
1526     if( window )
1527         window_name = window->name;
1528
1529     __END__;
1530
1531     return window_name;
1532 }
1533
1534
1535
1536 CV_IMPL void
1537 cvSetPreprocessFuncWin32(int (__cdecl *on_preprocess)(HWND, UINT, WPARAM, LPARAM, int*))
1538 {
1539     if(on_preprocess)
1540         hg_on_preprocess = on_preprocess;
1541     else
1542         assert(on_preprocess);
1543 }
1544
1545 CV_IMPL void
1546 cvSetPostprocessFuncWin32(int (__cdecl *on_postprocess)(HWND, UINT, WPARAM, LPARAM, int*))
1547 {
1548     if(on_postprocess)
1549         hg_on_postprocess = on_postprocess;
1550     else
1551         assert(on_postprocess);
1552 }
1553
1554 #endif //WIN32