]> git.saurik.com Git - wxWidgets.git/blob - src/msw/minifram.cpp
Fixed core dump for when there is no image list on the TreeCtrl
[wxWidgets.git] / src / msw / minifram.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: minifram.cpp
3 // Purpose: wxMiniFrame
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "minifram.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #include "wx/window.h"
24 #include "wx/msw/private.h"
25
26 #ifndef WX_PRECOMP
27 #include "wx/setup.h"
28 #include "wx/event.h"
29 #include "wx/app.h"
30 #include "wx/utils.h"
31 #endif
32
33 #if wxUSE_ITSY_BITSY
34
35 #include "wx/minifram.h"
36
37 #ifndef __TWIN32__
38 #ifdef __GNUWIN32__
39 #include "wx/msw/gnuwin32/extra.h"
40 #endif
41 #endif
42
43 #if !USE_SHARED_LIBRARY
44 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame, wxFrame)
45 #endif
46
47 long wxMiniFrame::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
48 {
49 if ((GetWindowStyleFlag() & wxTINY_CAPTION_HORIZ) ||
50 (GetWindowStyleFlag() & wxTINY_CAPTION_VERT))
51 return ::ibDefWindowProc((HWND) GetHWND(), nMsg, wParam, lParam);
52 else if ( m_oldWndProc )
53 return ::CallWindowProc(CASTWNDPROC m_oldWndProc, (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
54 else
55 return ::DefWindowProc((HWND) GetHWND(), nMsg, wParam, lParam);
56 }
57
58 wxMiniFrame::~wxMiniFrame(void)
59 {
60 }
61
62 /////////////////////////////////////////////////////////////////////////
63 //
64 // Project: ItsyBitsy window support module
65 // Module: itsybits.c
66 //
67 //
68 // ItsyBitsy is a support module that allows you to create windows
69 // that look and act very much like a popup window witha system
70 // menu and caption bar, except everything is scaled to about 2/3
71 // scale.
72 //
73 // For documentation on how to use ItsyBits, read the document
74 // ITSYBITS.DOC.
75 //
76 // Revisions:
77 // 9/27/91 Charlie Kindel (cek/ckindel)
78 // Wrote and documented it.
79 //
80 // 1/14/93 cek
81 // 2/23/93 cek Added minimize/maximize buttons.
82 // 3/18/93 cek Fixed system menu bug where system menu
83 // popped back up if you clicked on the
84 // icon again while it was up.
85 // 3/24/93 cek More comments. Fixed DS_MODALDIALOG style
86 // problem. Use auto precompiled headers
87 // in MSVC.
88 //
89 //////////////////////////////////////////////////////////////////////////
90
91 #include "wx/window.h"
92 #include "wx/msw/private.h"
93
94 #include <string.h>
95
96 #if !defined( __WATCOMC__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
97 #include <memory.h>
98 #endif
99
100 #include <stdlib.h>
101
102 #ifndef _RGB_H_
103 #define _RGB_H_
104
105 // Some mildly useful macros for the standard 16 colors
106 #define RGBBLACK RGB(0,0,0)
107 #define RGBRED RGB(128,0,0)
108 #define RGBGREEN RGB(0,128,0)
109 #define RGBBLUE RGB(0,0,128)
110
111 #define RGBBROWN RGB(128,128,0)
112 #define RGBMAGENTA RGB(128,0,128)
113 #define RGBCYAN RGB(0,128,128)
114 #define RGBLTGRAY RGB(192,192,192)
115
116 #define RGBGRAY RGB(128,128,128)
117 #define RGBLTRED RGB(255,0,0)
118 #define RGBLTGREEN RGB(0,255,0)
119 #define RGBLTBLUE RGB(0,0,255)
120
121 #define RGBYELLOW RGB(255,255,0)
122 #define RGBLTMAGENTA RGB(255,0,255)
123 #define RGBLTCYAN RGB(0,255,255)
124 #define RGBWHITE RGB(255,255,255)
125 #endif
126
127 #ifndef GlobalAllocPtr
128 #define GlobalPtrHandle(lp) \
129 ((HGLOBAL)GlobalHandle(lp))
130
131 #define GlobalLockPtr(lp) \
132 ((BOOL)GlobalLock(GlobalPtrHandle(lp)))
133 #define GlobalUnlockPtr(lp) \
134 GlobalUnlock(GlobalPtrHandle(lp))
135
136 #define GlobalAllocPtr(flags, cb) \
137 (GlobalLock(GlobalAlloc((flags), (cb))))
138 #define GlobalReAllocPtr(lp, cbNew, flags) \
139 (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags))))
140 #define GlobalFreePtr(lp) \
141 (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))
142 #endif
143
144 #if defined(__BORLANDC__) || defined(__WATCOMC__)
145 #define max(a,b) (((a) > (b)) ? (a) : (b))
146 #define min(a,b) (((a) < (b)) ? (a) : (b))
147 #endif
148
149 // CAPTIONXY is the default size of the system menu icon. This
150 // determines the height/width of the caption.
151 //
152 // The value that results from the following formula works out
153 // nicely for the veritcal caption on VGA, 8514 (Large Fonts),
154 // 8514 (Small Fonts), XGA (Small Fonts), XGA (Large Fonts),
155 // and TIGA (Small Fonts). It may not be good on other displays.
156 //
157 // The problem is that TT fonts turn into bitmap fonts when they
158 // are sized below a certain threshold. The idea is to make the
159 // size of the caption just big enough to get the smallest TT
160 // (scalable) font to fit.
161 //
162 #define CAPTIONXY (GetSystemMetrics( SM_CYCAPTION ) / 2 + 1)
163
164 #define TestWinStyle( hWnd, dwStyleBit ) \
165 (((DWORD)GetWindowLong( hWnd, GWL_STYLE ) & (DWORD)dwStyleBit) ? TRUE : FALSE )
166 #define HASCAPTION( hwnd ) (TestWinStyle( hwnd, IBS_VERTCAPTION ) ||\
167 TestWinStyle( hwnd, IBS_HORZCAPTION ))
168
169 #define SETCAPTIONSIZE(h,i) (UINT)SetProp(h,_T("ibSize"),(HANDLE)i)
170 #define GETCAPTIONSIZE(h) (UINT)GetProp(h,_T("ibSize"))
171 #define FREECAPTIONSIZE(h) RemoveProp(h,_T("ibSize"))
172
173 #define SETMENUWASUPFLAG(h,i) (UINT)SetProp(h,_T("ibFlag"),(HANDLE)i)
174 #define GETMENUWASUPFLAG(h) (UINT)GetProp(h,_T("ibFlag"))
175 #define FREEMENUWASUPFLAG(h) RemoveProp(h,_T("ibFlag"))
176
177 /////////////////////////////////////////////////////////////////////
178 // Little known fact:
179 // ExtTextOut() is the fastest way to draw a filled rectangle
180 // in Windows (if you don't want dithered colors or borders).
181 //
182 // Unfortunately there is a bug in the Windows 3.0 8514 driver
183 // in using ExtTextOut() to a memory DC. If you are drawing
184 // to an off screen bitmap, then blitting that bitmap to the
185 // display, do not #define wxUSE_EXTTEXTOUT below.
186 //
187 // The following macro (DRAWFASTRECT) draws a filled rectangle
188 // with no border and a solid color. It uses the current back-
189 // ground color as the fill color.
190 //////////////////////////////////////////////////////////////////////
191 #define wxUSE_EXTTEXTOUT
192 #ifdef wxUSE_EXTTEXTOUT
193 #define DRAWFASTRECT(hdc,lprc) ExtTextOut(hdc,0,0,ETO_OPAQUE,lprc,NULL,0,NULL)
194 #else
195 #define DRAWFASTRECT(hdc,lprc) {\
196 HBRUSH hbr = CreateSolidBrush( GetBkColor( hdc ) ) ;\
197 hbr = SelectObject(hdc, hbr) ;\
198 PatBlt(hdc,(lprc)->left,(lprc)->top,(lprc)->right-(lprc)->left,(lprc)->bottom-(lprc)->top,PATCOPY) ;\
199 hbr = SelectObject(hdc, hbr) ;\
200 DeleteObject( hbr ) ;\
201 }
202 #endif
203
204 // The DrawArrow function takes the following to indicate what
205 // kind of arrow to draw.
206 //
207 #define ARROW_UP 0
208 #define ARROW_DOWN 1
209 #define ARROW_RESTORE 2
210
211 BOOL PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT ) ;
212 BOOL PASCAL DoMenu( HWND hWnd ) ;
213 void PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu ) ;
214 BOOL PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc ) ;
215 BOOL PASCAL GetIconRect( HWND hWnd, LPRECT lprc ) ;
216 BOOL PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc ) ;
217 BOOL PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc ) ;
218 BOOL PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc ) ;
219 BOOL PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
220 BOOL fVert, BOOL fSysMenu,
221 BOOL fMin, BOOL fMax, BOOL fActive ) ;
222 void PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert ) ;
223 void PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed ) ;
224 void PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle ) ;
225
226 // Global vars
227 //
228 static BOOL fWin31 ;
229
230 ///////////////////////////////////////////////////////////////////////
231 // External/Public functions
232 ///////////////////////////////////////////////////////////////////////
233
234 /////////////////////////////////////////////////////////////////
235 // UINT WINAPI ibGetCaptionSize( HWND hWnd )
236 //
237 // Description:
238 //
239 // Gets the size of the caption (height if horz, width if
240 // vertical).
241 //
242 // Comments:
243 //
244 ///////////////////////////////////////////////////////////////
245 UINT WINAPI ibGetCaptionSize( HWND hWnd )
246 {
247 return GETCAPTIONSIZE( hWnd ) + 1 ;
248 } // ibSetCaptionSize()
249
250 /////////////////////////////////////////////////////////////////
251 // UINT WINAPI ibSetCaptionSize( HWND hWnd, UINT nSize )
252 //
253 // Description:
254 //
255 // Changes the size of the caption (height if horz, width if
256 // vertical).
257 //
258 // Comments:
259 //
260 //////////////////////////////////////////////////////////////////
261 UINT WINAPI ibSetCaptionSize( HWND hWnd, UINT nSize )
262 {
263 UINT ui ;
264
265 if (nSize <= 0)
266 return 0 ;
267
268 nSize-- ;
269 ui = SETCAPTIONSIZE( hWnd, nSize ) ;
270
271 // Once we change the window style, we need a WM_NCCALCRECT
272 // to be generated.
273 //
274 // SWP_FRAMECHANGED is not documented in the 3.1 SDK docs,
275 // but *is* in WINDOWS.H.
276 //
277 SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED |
278 SWP_NOSIZE | SWP_NOMOVE |
279 SWP_NOACTIVATE | SWP_NOZORDER) ;
280
281 return ui ;
282
283 } // ibSetCaptionSize()
284
285 /////////////////////////////////////////////////////////////////
286 // LRESULT WINAPI ibDefWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
287 //
288 // Description:
289 //
290 // This function should be called instead of DefWindowProc() for
291 // windows that want to have itsybitsy captions.
292 //
293 // Comments:
294 //
295 //////////////////////////////////////////////////////////////////
296 LRESULT WINAPI ibDefWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
297 {
298 LRESULT lRet ;
299 UINT nCapSize ;
300
301 switch( uiMsg )
302 {
303 case WM_SYSCHAR:
304 // If ALT-SPACE
305 // was hit then pop up the menu
306 //
307 if (HASCAPTION( hWnd ) && (wParam == VK_SPACE))
308 {
309 DoMenu( hWnd ) ;
310 break ;
311 }
312
313 // FALL THROUGH!!!!
314 //
315
316 case WM_SYSKEYDOWN:
317 case WM_SYSKEYUP:
318 case WM_KEYDOWN:
319 case WM_KEYUP:
320 {
321 DWORD dw = GetWindowLong( hWnd, GWL_STYLE ) ;
322
323 // Fool DefWindowProc into thinking we do not have
324 // a system menu. Otherwise it will try to
325 // pop up its own.
326 //
327 SetWindowLong( hWnd, GWL_STYLE, dw &~WS_SYSMENU ) ;
328 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
329 SetWindowLong( hWnd, GWL_STYLE, dw ) ;
330 return lRet ;
331 }
332 break ;
333
334 case WM_COMMAND:
335 // The menu that is poped up for the system menu with
336 // TrackPopupMenu() sends it's notifications as WM_COMMAND
337 // messages. We need to translate these into
338 // WM_SYSCOMMAND messages. All standard WM_SYSCOMMAND
339 // ids are greater than 0xF000.
340 //
341 // This could be a possible cause of confusion if the
342 // itsybitsy window had children that used SC_MOVE or SC_CLOSE
343 // as their IDs. Take note and be careful.
344 //
345 // Also, because ibDefWindowProc looks at WM_COMMAND messages,
346 // you will need to be careful to call ibDefWindowProc() for
347 // any wm_command messages that you would normally ignore.
348 // Otherwise the system menu won't work.
349 //
350 if (wParam >= 0xF000)
351 // Call PostMessage() here instead of SendMessage!
352 // Here's why:
353 // Our menu was created by TrackPopupMenu(). TPM() does
354 // not return until after the menu has been destroyed
355 // (and thus the command associated with the menu selection
356 // sent). Therefore when we get here, we are still
357 // *inside* TPM(). If we Send WM_SYSCOMMAND, SC_CLOSE
358 // to the window, the window will be destroyed before
359 // TPM() returns to our code within DoMenu() below. Wel...
360 // We do stuff with the window handle after DoMenu()
361 // returns (namely GetProp()). Since the window has
362 // been destroyed,this is bad.
363 PostMessage( hWnd, WM_SYSCOMMAND, wParam, lParam ) ;
364
365 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
366
367 case WM_GETMINMAXINFO:
368 {
369 nCapSize = GETCAPTIONSIZE( hWnd ) ;
370 if (HASCAPTION( hWnd ) && TestWinStyle( hWnd, WS_THICKFRAME ))
371 {
372 LPPOINT lppt = (LPPOINT)lParam ;
373 RECT rcMenu ;
374 RECT rcMin ;
375 RECT rcMax ;
376 int nX ;
377 int cx, cy ; // window frame/border width
378
379 if (TestWinStyle( hWnd, WS_THICKFRAME ))
380 {
381 cx = GetSystemMetrics( SM_CXFRAME ) ;
382 cy = GetSystemMetrics( SM_CYFRAME ) ;
383 }
384 else if (TestWinStyle(hWnd, WS_BORDER ))
385 {
386 cx = GetSystemMetrics( SM_CXBORDER ) ;
387 cy = GetSystemMetrics( SM_CYBORDER ) ;
388 }
389 else
390 {
391 // VZ: I don't know what should be here, but the vars must
392 // be inited!
393 wxFAIL_MSG(_T("don't know how to initialize cx, cy"));
394
395 cx = cy = 0;
396 }
397
398 GetIconRect( hWnd, &rcMenu ) ;
399 GetMinButtonRect( hWnd, &rcMin ) ;
400 GetMaxButtonRect( hWnd, &rcMax ) ;
401 nX = (rcMenu.right-rcMenu.left) +
402 (rcMin.right-rcMin.left) +
403 (rcMin.right-rcMin.left) ;
404
405
406 if (TestWinStyle( hWnd, IBS_VERTCAPTION ) )
407 {
408 lppt[3].x = nCapSize + cx * 2 - 1 ;
409 lppt[3].y = nX + (2* nCapSize) ;
410 }
411 else
412 {
413 lppt[3].x = nX + (2* nCapSize) ;
414 lppt[3].y = nCapSize + cy * 2 - 1 ;
415 }
416 }
417 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
418 }
419 break ;
420
421 /////////////////////////////////////////////////////////////////////
422 // Non-client area messages. These are used to allow the
423 // minature caption bar to be handled correctly.
424 //
425 case WM_NCCREATE:
426 {
427 DWORD dwStyle ;
428
429 // We have two things that we need to store somewhere:
430 // 1) The caption height (width).
431 // and 2) A flag indicating whether the sysmenu was
432 // just up or not.
433 //
434 // CAPTIONXY is a macro that calls GetSystemMetrics.
435 //
436 SETCAPTIONSIZE( hWnd, CAPTIONXY ) ;
437
438 // Set our flag that tells us whether the system menu was
439 // 'just up'.
440 //
441 SETMENUWASUPFLAG( hWnd, FALSE ) ;
442
443 // Are we in 3.1? If so we have some neat features
444 // we can use like rotated TrueType fonts.
445 //
446 fWin31 = (BOOL)(LOWORD( GetVersion() ) >= 0x030A) ;
447
448 // If IBS_????CAPTION was specified and the WS_DLGFRAME (or
449 // WS_DLGFRAME 'cause it == WS_CAPTION | WS_BORDER)
450 // was specified the creator made a mistake. Things get really
451 // ugly if DefWindowProc sees WS_DLGFRAME, so we strip
452 // the WS_DLGFRAME part off!
453 //
454 dwStyle = GetWindowLong( hWnd, GWL_STYLE ) ;
455 if ((dwStyle & IBS_VERTCAPTION || dwStyle & IBS_HORZCAPTION) &&
456 dwStyle & WS_DLGFRAME)
457 {
458 dwStyle &= (DWORD)~WS_DLGFRAME ;
459 SetWindowLong( hWnd, GWL_STYLE, dwStyle ) ;
460 }
461 }
462 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
463
464 case WM_NCDESTROY:
465 // We store the caption size in a window prop. so we
466 // must remove props.
467 //
468 FREECAPTIONSIZE( hWnd ) ;
469 FREEMENUWASUPFLAG( hWnd ) ;
470 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
471
472 case WM_NCCALCSIZE:
473 // This is sent when the window manager wants to find out
474 // how big our client area is to be. If we have a mini-caption
475 // then we trap this message and calculate the cleint area rect,
476 // which is the client area rect calculated by DefWindowProc()
477 // minus the width/height of the mini-caption bar
478 //
479 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
480 if (!IsIconic( hWnd ) && HASCAPTION( hWnd ))
481 {
482 nCapSize = GETCAPTIONSIZE( hWnd ) ;
483
484 if (TestWinStyle( hWnd, IBS_VERTCAPTION ) )
485 ((LPRECT)lParam)->left += nCapSize ;
486 else
487 ((LPRECT)lParam)->top += nCapSize ;
488 }
489 return lRet ;
490
491 case WM_NCHITTEST:
492 // This message is sent whenever the mouse moves over us.
493 // We will depend on DefWindowProc for everything unless
494 // there is a mini-caption, in which case we will
495 // return HTCAPTION or HTSYSMENU. When the user clicks
496 // or double clicks, NC_LBUTTON/ message are sent with
497 // wParam equal to what we return here.
498 // This means that this is an ideal place to figure out
499 // where we are!
500 //
501 // let defwindowproc handle the standard borders etc...
502 //
503 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
504 if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && lRet == HTNOWHERE)
505 {
506 RECT rc ;
507 RECT rcMenu ;
508 RECT rcMinButton ;
509 RECT rcMaxButton ;
510 POINT pt ;
511
512 nCapSize = GETCAPTIONSIZE( hWnd ) ;
513
514 // if DefWindowProc returned HTCAPTION then we have to
515 // refine the area and return HTSYSMENU if appropriate
516 //
517 pt.x = LOWORD( lParam ) ;
518 pt.y = HIWORD( lParam ) ;
519
520 GetCaptionRect( hWnd, &rc ) ; // window coords
521 if (PtInRect( &rc, pt ))
522 {
523 lRet = HTCAPTION ;
524
525 // rely on the fact that Get???Rect() return an invalid
526 // (empty) rectangle if the menu/buttons don't exist
527 //
528 GetIconRect( hWnd, &rcMenu ) ;
529 GetMinButtonRect( hWnd, &rcMinButton ) ;
530 GetMaxButtonRect( hWnd, &rcMaxButton ) ;
531
532 if (PtInRect( &rcMenu, pt ))
533 lRet = HTSYSMENU ;
534
535 if (PtInRect( &rcMinButton, pt ))
536 lRet = HTMINBUTTON ;
537 else
538 if (PtInRect( &rcMaxButton, pt ))
539 lRet = HTMAXBUTTON ;
540 }
541 }
542 if (lRet != HTSYSMENU)
543 SETMENUWASUPFLAG( hWnd, FALSE ) ;
544 return lRet ;
545
546 case WM_NCLBUTTONDBLCLK:
547 // Windows recieve WM_NC?BUTTONDBLCLK messages whether they
548 // have CS_DBLCLKS or not. We watch for one of these
549 // to see if the user double clicked on the system menu (to
550 // close the window) or on the caption (to maximize the window).
551 //
552 if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && wParam == HTSYSMENU)
553 {
554 SendMessage( hWnd, WM_CLOSE, 0, 0L ) ;
555 break ;
556 }
557 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
558
559 case WM_NCLBUTTONDOWN:
560 {
561 RECT rc ;
562
563 // If we're iconic or we don't have a caption then
564 // DefWindowProc will do the job just fine.
565 //
566 if (IsIconic( hWnd ) || !HASCAPTION( hWnd ))
567 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
568
569 // Here's were we handle the system menu, the min and max buttons.
570 // If you wanted to change the behavior of the min/max buttons
571 // do something like swap tool palettes or something, you
572 // would change the SendMessage() calls below.
573 //
574 switch (wParam)
575 {
576 case HTSYSMENU:
577 if (GETMENUWASUPFLAG( hWnd ) == FALSE && DoMenu( hWnd ))
578 SETMENUWASUPFLAG( hWnd, TRUE ) ;
579 else
580 SETMENUWASUPFLAG( hWnd, FALSE ) ;
581 break ;
582
583 case HTMINBUTTON:
584 GetMinButtonRect( hWnd, &rc ) ;
585 // Note that DepressMinMaxButton() goes into
586 // a PeekMessage() loop waiting for the mouse
587 // to come back up.
588 //
589 if (DepressMinMaxButton( hWnd, wParam, &rc ))
590 SendMessage( hWnd, WM_SYSCOMMAND, SC_MINIMIZE, lParam ) ;
591 break ;
592
593 case HTMAXBUTTON:
594 GetMaxButtonRect( hWnd, &rc ) ;
595 // Note that DepressMinMaxButton() goes into
596 // a PeekMessage() loop waiting for the mouse
597 // to come back up.
598 //
599 if (DepressMinMaxButton( hWnd, wParam, &rc ))
600 {
601 if (IsZoomed(hWnd))
602 SendMessage( hWnd, WM_SYSCOMMAND, SC_RESTORE, lParam ) ;
603 else
604 SendMessage( hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, lParam ) ;
605 }
606 break ;
607
608 default:
609 // Well, it appears as though the user clicked somewhere other
610 // than the buttons. We let DefWindowProc do it's magic.
611 // This is where things like dragging and sizing the
612 // window happen.
613 //
614 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
615 }
616 }
617 break ;
618
619 case WM_NCPAINT:
620 case WM_NCACTIVATE:
621 if (IsIconic( hWnd ))
622 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
623
624 // Paint the non-client area here. We will call DefWindowProc
625 // after we are done so it can paint the borders and so
626 // forth...
627 //
628 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
629 if (HASCAPTION( hWnd ))
630 {
631 RECT rcCap ;
632 RECT rc ;
633 HDC hDC = GetWindowDC( hWnd ) ;
634 BOOL fActive ;
635
636 GetCaptionRect( hWnd, &rcCap ) ; // Convert to window coords
637 GetWindowRect( hWnd, &rc ) ;
638 OffsetRect( &rcCap, -rc.left, -rc.top ) ;
639
640 if (uiMsg == WM_NCPAINT)
641 fActive = (hWnd == GetActiveWindow()) ;
642 else
643 fActive = wParam ;
644
645 DrawCaption( hDC, hWnd, &rcCap,
646 TestWinStyle(hWnd, IBS_VERTCAPTION),
647 TestWinStyle(hWnd, WS_SYSMENU),
648 TestWinStyle(hWnd, WS_MINIMIZEBOX),
649 TestWinStyle(hWnd, WS_MAXIMIZEBOX),
650 fActive ) ;
651
652 ReleaseDC( hWnd, hDC ) ;
653 }
654 return lRet;
655 break;
656
657 default:
658 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
659 }
660
661 return 0L ;
662
663 } // ibDefWindowProc()
664
665 // ibAdjustWindowRect( HWND hWnd, LPRECT lprc )
666 //
667 // Does the same thing as the USER function AdjustWindowRect(),
668 // but knows about itsybitsy windows. AdjustWindowRect() is
669 // bogus for stuff like this.
670 //
671 void WINAPI ibAdjustWindowRect( HWND hWnd, LPRECT lprc )
672 {
673 short cx = 0, cy = 0 ;
674 UINT nCapSize ;
675
676 nCapSize = GETCAPTIONSIZE( hWnd ) ;
677
678 // First check Windows's styles, then our own.
679 //
680 if (TestWinStyle( hWnd, WS_THICKFRAME ))
681 {
682 cx = GetSystemMetrics( SM_CXFRAME ) ;
683 cy = GetSystemMetrics( SM_CYFRAME ) ;
684 }
685 else
686 if (TestWinStyle(hWnd, DS_MODALFRAME ))
687 {
688 cx = GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ;
689 cy = GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ;
690 }
691 else
692 if (TestWinStyle(hWnd, WS_BORDER ))
693 {
694 cx = GetSystemMetrics( SM_CXBORDER ) ;
695 cy = GetSystemMetrics( SM_CYBORDER ) ;
696 }
697
698 InflateRect( lprc, cx, cy ) ;
699
700 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
701 lprc->left -= nCapSize ;
702 else
703 if (TestWinStyle( hWnd, IBS_HORZCAPTION ))
704 lprc->top -= nCapSize ;
705
706 } // ibAdjustWindowRect()
707
708
709 ///////////////////////////////////////////////////////////////////////
710 // Internal functions
711 ///////////////////////////////////////////////////////////////////////
712
713 // DepressMinMaxButton()
714 //
715 // This function is called when the user has pressed either the min or
716 // max button (i.e. WM_NCLBUTTONDOWN). We go into a Peekmessage() loop,
717 // waiting for the mouse to come back up. This allows us to make the
718 // button change up/down state like a real button does.
719 //
720 // lprc points to the rectangle that describes the button the
721 // user has clicked on.
722 //
723 BOOL PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT lprc )
724 {
725 BOOL fDepressed = TRUE ;
726 MSG msg ;
727
728 // Draw button in down state
729 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed ) ;
730 SetCapture( hWnd ) ;
731
732 while (TRUE)
733 {
734 if (PeekMessage((LPMSG)&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
735 {
736 switch (msg.message)
737 {
738 case WM_LBUTTONUP:
739 if (fDepressed)
740 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, !fDepressed ) ;
741 ReleaseCapture();
742 return PtInRect( lprc, msg.pt ) ;
743
744 case WM_MOUSEMOVE:
745 if (PtInRect( lprc, msg.pt ))
746 {
747 if (!fDepressed)
748 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = TRUE ) ;
749 }
750 else
751 {
752 if (fDepressed)
753 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = FALSE ) ;
754 }
755 break;
756 }
757 }
758 }
759
760 } // DepressMinMaxButton()
761
762 // DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
763 // BOOL fVert, BOOL fSysMenu, BOOL fActive )
764 //
765 // This function draws an itsy bitsy caption bar with or
766 // without system menu to the dc specified by hDC. The
767 // caption is drawn to fit within the lprc RECT and is
768 // drawn//withOut/ borders.
769 //
770 BOOL PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
771 BOOL fVert, BOOL fSysMenu, BOOL fMin,
772 BOOL fMax, BOOL fActive )
773 {
774 RECT rc ;
775 RECT rcCap ;
776 COLORREF rgbCaptionBG ;
777 COLORREF rgbText ;
778 COLORREF rgbWindowFrame ;
779 HBRUSH hbrCaption ;
780 UINT ui ;
781 UINT nCapSize ;
782
783 nCapSize = GETCAPTIONSIZE( hWnd ) ;
784
785 // Get the colors.
786 //
787 rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
788
789 // if we have focus use the active caption color
790 // otherwise use the inactive caption color
791 //
792 if (fActive)
793 {
794 rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ;
795 rgbCaptionBG = GetSysColor( COLOR_ACTIVECAPTION ) ;
796 }
797 else
798 {
799 if (fWin31)
800 rgbText = GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ;
801 else
802 rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ;
803
804 rgbCaptionBG = GetSysColor( COLOR_INACTIVECAPTION ) ;
805 }
806
807 SetBkMode( hDC, TRANSPARENT ) ;
808 SelectObject( hDC, GetStockObject( NULL_BRUSH ) ) ;
809 SelectObject( hDC, GetStockObject( NULL_PEN ) ) ;
810
811 rcCap = *lprc ;
812
813 if (fSysMenu)
814 {
815 if (fVert)
816 rcCap.top += nCapSize ;
817 else
818 rcCap.left += nCapSize ;
819 }
820
821 if (fMax)
822 {
823 if (fVert)
824 rcCap.bottom -= nCapSize ;
825 else
826 rcCap.right -= nCapSize ;
827 }
828
829 if (fMin)
830 {
831 if (fVert)
832 rcCap.bottom -= nCapSize ;
833 else
834 rcCap.right -= nCapSize ;
835 }
836
837 if (fVert)
838 {
839 rc.left = lprc->right - 1 ;
840 rc.right = lprc->right ;
841 rc.top = lprc->top ;
842 rc.bottom = lprc->bottom ;
843 }
844 else
845 {
846 rc.left = lprc->left ;
847 rc.right = lprc->right ;
848 rc.bottom = lprc->bottom ;
849 rc.top = rc.bottom - 1 ;
850 }
851
852 SetBkColor( hDC, rgbWindowFrame ) ;
853 DRAWFASTRECT( hDC, &rc ) ;
854
855 hbrCaption = CreateSolidBrush( rgbCaptionBG ) ;
856 hbrCaption = (HBRUSH) SelectObject( hDC, hbrCaption ) ;
857 SelectObject( hDC, (HPEN) GetStockObject( NULL_PEN ) ) ;
858 if (fVert)
859 Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right, rcCap.bottom + 1 ) ;
860 else
861 Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right+1, rcCap.bottom ) ;
862 hbrCaption = (HBRUSH) SelectObject( hDC, hbrCaption ) ;
863 DeleteObject( hbrCaption ) ;
864
865
866 // Draw caption text here. Only do it in 3.1 'cause 3.1 gives
867 // us 'small fonts'.
868 //
869 ui = GetWindowTextLength( hWnd ) ;
870 if (fWin31)
871 {
872 HFONT hFont ;
873 LPTSTR lpsz ;
874 LOGFONT lf ;
875 TEXTMETRIC tm ;
876 int cx ;
877 int cy ;
878 SIZE Size ;
879
880 lpsz = (wxChar*)GlobalAllocPtr( GHND, (ui + 2) * sizeof(wxChar) );
881 if (lpsz)
882 {
883 UINT nBkMode ;
884
885 GetWindowText( hWnd, lpsz, ui + 1 ) ;
886 nBkMode = SetBkMode( hDC, TRANSPARENT ) ;
887 rgbText = SetTextColor( hDC, rgbText ) ;
888
889 memset( &lf, '\0', sizeof(LOGFONT) ) ;
890
891 lf.lfHeight = -(int)(nCapSize - 3) ;
892 lf.lfCharSet = ANSI_CHARSET ;
893 lf.lfQuality = DEFAULT_QUALITY ;
894 lf.lfClipPrecision = CLIP_LH_ANGLES | CLIP_STROKE_PRECIS ;
895 if (nCapSize >= 20)
896 {
897 lf.lfWeight = FW_BOLD ;
898 }
899
900 if (fVert)
901 {
902 // Can only rotate true type fonts (well, ok, we could
903 // try and use "modern").
904 wxStrcpy( lf.lfFaceName, _T("Arial") ) ;
905 lf.lfPitchAndFamily = FF_SWISS | 0x04;
906 lf.lfEscapement = 900 ;
907
908 // Note: The Win 3.1 documentation for CreateFont() say's
909 // that the lfOrientation member is ignored. It appears,
910 // that on Windows 16 3.1 this is true, but when running
911 // as a 16 bit WinApp on WindowsNT 3.1 the lfOrientation
912 // must be set or the text does not rotate!
913 //
914 lf.lfOrientation = 900 ;
915
916 hFont = CreateFontIndirect( &lf ) ;
917 hFont = (HFONT) SelectObject( hDC, hFont ) ;
918
919 GetTextExtentPoint( hDC, lpsz, ui, &Size ) ;
920 cx = rcCap.bottom - ((rcCap.bottom - rcCap.top - Size.cx) / 2) ;
921 cy = rcCap.left - 1 + ((rcCap.right - rcCap.left - Size.cy) / 2) ;
922
923 // Make sure we got a rotatable font back.
924 //
925 GetTextMetrics( hDC, &tm ) ;
926 if (tm.tmPitchAndFamily & TMPF_VECTOR ||
927 tm.tmPitchAndFamily & TMPF_TRUETYPE)
928 {
929 ExtTextOut( hDC,
930 cy,
931 min( (long)cx, rcCap.bottom),
932 ETO_CLIPPED, &rcCap,
933 lpsz, ui, NULL ) ;
934 }
935
936 hFont = (HFONT) SelectObject( hDC, hFont ) ;
937 DeleteObject( hFont ) ;
938 }
939 else
940 {
941 // Use small fonts always for the horizontal. Cause it looks
942 // more like "System" than Arial.
943 //
944 lf.lfPitchAndFamily = FF_SWISS ;
945
946 hFont = CreateFontIndirect( &lf ) ;
947 hFont = (HFONT) SelectObject( hDC, hFont ) ;
948
949 GetTextExtentPoint( hDC, lpsz, ui, &Size ) ;
950 cx = rcCap.left + ((rcCap.right - rcCap.left - Size.cx) / 2) ;
951 cy = rcCap.top + ((rcCap.bottom - rcCap.top - Size.cy) / 2) ;
952
953 // Figger out how big the string is
954 //
955 ExtTextOut( hDC,
956 max( (long)cx, rcCap.left ),
957 cy,
958 ETO_CLIPPED, &rcCap,
959 lpsz, ui, NULL ) ;
960
961 hFont = (HFONT) SelectObject( hDC, hFont ) ;
962 DeleteObject( hFont ) ;
963 }
964
965 // Unsetup the DC
966 //
967 rgbText = SetTextColor( hDC, rgbText ) ;
968 SetBkMode( hDC, nBkMode ) ;
969
970 #ifdef __WIN16__
971 GlobalFreePtr( (unsigned int) lpsz ) ;
972 #else
973 GlobalFreePtr( lpsz ) ;
974 #endif
975 }
976 }
977
978 if (fSysMenu)
979 DrawSysMenu( hDC, hWnd, FALSE ) ;
980
981 if (fMin)
982 DrawButton( hDC, hWnd, TRUE, FALSE ) ;
983
984 if (fMax)
985 DrawButton( hDC, hWnd, FALSE, FALSE ) ;
986
987 return TRUE ;
988
989 } // DrawCaption()
990
991
992 // DrawSysMenu( HDC hDC, hWnd, BOOL fInvert )
993 //
994 // Draws the little system menu icon.
995 //
996 void PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert )
997 {
998 RECT rcIcon ;
999 RECT rcTemp ;
1000 RECT rc ;
1001 COLORREF rgbIconFace ;
1002 COLORREF rgbWindowFrame ;
1003 BOOL fDC ;
1004 UINT nCapSize ;
1005
1006 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1007
1008 if (!hDC)
1009 {
1010 fDC = TRUE ;
1011 hDC = GetWindowDC( hWnd ) ;
1012 }
1013 else
1014 fDC = FALSE ;
1015
1016 if (hDC)
1017 {
1018 rgbIconFace = GetNearestColor( hDC, RGBLTGRAY ) ;
1019 rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
1020
1021 GetIconRect( hWnd, &rcIcon ) ;
1022 GetWindowRect( hWnd, &rc ) ;
1023
1024 OffsetRect( &rcIcon, -rc.left, -rc.top ) ;
1025
1026 rcTemp = rcIcon ;
1027
1028 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1029 {
1030 rc = rcIcon ; // separator line
1031 rc.top = ++rc.bottom - 1 ;
1032 }
1033 else
1034 {
1035 rc = rcIcon ; // separator line
1036 rc.left = ++rc.right - 1 ;
1037 }
1038
1039 // Fill
1040 SetBkColor( hDC, rgbIconFace ) ;
1041 DRAWFASTRECT( hDC, &rcTemp ) ;
1042
1043 // Draw separator line
1044 SetBkColor( hDC, rgbWindowFrame ) ;
1045 DRAWFASTRECT( hDC, &rc ) ;
1046
1047 if (nCapSize > 4)
1048 {
1049 // Draw the little horizontal doo-hickey
1050 //
1051 rcTemp.top = rcIcon.top + ((nCapSize-1) / 2) ;
1052 rcTemp.bottom = rcTemp.top + 3 ;
1053 rcTemp.left = rcTemp.left + 3 ;
1054 rcTemp.right = rcTemp.right - 1 ;
1055
1056 SetBkColor( hDC, RGBGRAY ) ;
1057 DRAWFASTRECT( hDC, &rcTemp ) ;
1058
1059 rc = rcTemp ;
1060 OffsetRect( &rc, -1, -1 ) ;
1061 SetBkColor( hDC, RGBBLACK ) ;
1062 DRAWFASTRECT( hDC, &rc ) ;
1063
1064 InflateRect( &rc, -1, -1 ) ;
1065 SetBkColor( hDC, RGBWHITE ) ;
1066 DRAWFASTRECT( hDC, &rc ) ;
1067 }
1068
1069 if (fInvert)
1070 InvertRect( hDC, &rcIcon ) ;
1071
1072 if (fDC)
1073 ReleaseDC( hWnd, hDC ) ;
1074 }
1075
1076 } // DrawSysMenu()
1077
1078 // DoMenu( HWND hWnd )
1079 //
1080 // Pops up the system menu.
1081 //
1082 BOOL PASCAL DoMenu( HWND hWnd )
1083 {
1084 HDC hDC ;
1085 RECT rcIcon ;
1086 RECT rc ;
1087 POINT pt ;
1088 HMENU hMenu ;
1089 DWORD dw ;
1090
1091 if (!TestWinStyle(hWnd, WS_SYSMENU))
1092 return FALSE ;
1093
1094 hDC = GetWindowDC( hWnd );
1095 if (hDC)
1096 {
1097 // Invert the icon
1098 //
1099 DrawSysMenu( hDC, hWnd, TRUE ) ;
1100
1101 // Pop up the menu
1102 //
1103 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1104 {
1105 pt.x = -1 ;
1106 pt.y = 0 ;
1107 }
1108 else
1109 {
1110 pt.x = 0 ;
1111 pt.y = -1 ;
1112 }
1113
1114 GetIconRect( hWnd, &rcIcon ) ;
1115 GetWindowRect( hWnd, &rc ) ;
1116 OffsetRect( &rcIcon, -rc.left, -rc.top ) ;
1117
1118 ClientToScreen( hWnd, &pt ) ;
1119 ClientToScreen( hWnd, (LPPOINT)&rc.right ) ;
1120
1121 dw = GetWindowLong( hWnd, GWL_STYLE ) ;
1122 SetWindowLong( hWnd, GWL_STYLE, dw | WS_SYSMENU ) ;
1123
1124 hMenu = GetSystemMenu( hWnd, FALSE ) ;
1125 SetupSystemMenu( hWnd, hMenu ) ;
1126
1127 SetWindowLong( hWnd, GWL_STYLE, dw ) ;
1128
1129 TrackPopupMenu( hMenu, 0, //TPM_LEFTALIGN,
1130 pt.x,
1131 pt.y,
1132 0,
1133 hWnd,
1134 &rc ) ;
1135
1136 DrawSysMenu( hDC, hWnd, FALSE ) ;
1137 ReleaseDC( hWnd, hDC ) ;
1138 }
1139 return TRUE ;
1140
1141 } // DoMenu()
1142
1143 // SetupSystemMenu( HWND hWnd, HMENU hMenu )
1144 //
1145 // Enables/Disables the appropriate menu items on the
1146 // menu passed for the window passed.
1147 //
1148 void PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu )
1149 {
1150 UINT wMove ;
1151 UINT wSize ;
1152 UINT wMinBox ;
1153 UINT wMaxBox ;
1154 UINT wRestore ;
1155
1156 // Assume all should be grayed.
1157 //
1158 wSize = wMove = wMinBox = wMaxBox = wRestore = MF_GRAYED ;
1159
1160 if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ) || IsIconic( hWnd ))
1161 wMaxBox = MF_ENABLED ;
1162
1163 if (TestWinStyle( hWnd, WS_MINIMIZEBOX ))
1164 wMinBox = MF_ENABLED ;
1165
1166 if (IsZoomed( hWnd ))
1167 wRestore = MF_ENABLED ;
1168
1169 if (TestWinStyle( hWnd, WS_THICKFRAME ) &&
1170 !(IsIconic( hWnd ) || IsZoomed( hWnd )))
1171 wSize = MF_ENABLED ;
1172
1173 if (!IsZoomed( hWnd ) &&
1174 !IsIconic( hWnd ) &&
1175 TestWinStyle( hWnd, WS_CAPTION ) )
1176 wMove = MF_ENABLED ;
1177
1178 EnableMenuItem( hMenu, SC_MOVE, wMove ) ;
1179 EnableMenuItem( hMenu, SC_SIZE, wSize ) ;
1180 EnableMenuItem( hMenu, SC_MINIMIZE, wMinBox ) ;
1181 EnableMenuItem( hMenu, SC_MAXIMIZE, wMaxBox ) ;
1182 EnableMenuItem( hMenu, SC_RESTORE, wRestore ) ;
1183
1184 } // SetupSystemMenu()
1185
1186 // GetCaptionRect( HWND hWnd, LPRECT lprc )
1187 //
1188 // calcluales the rectangle of the mini-caption in screen coords.
1189 //
1190 BOOL PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc )
1191 {
1192 UINT nCapSize ;
1193
1194 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1195
1196 if (!HASCAPTION( hWnd ))
1197 {
1198 SetRectEmpty( lprc ) ;
1199 return FALSE ;
1200 }
1201
1202 GetWindowRect( hWnd, lprc ) ;
1203
1204 // the window might have other non-client components like
1205 // borders
1206 //
1207 if (TestWinStyle( hWnd, WS_THICKFRAME ))
1208 {
1209 lprc->left += GetSystemMetrics( SM_CXFRAME ) ;
1210 lprc->top += GetSystemMetrics( SM_CYFRAME ) ;
1211 lprc->right -= GetSystemMetrics( SM_CXFRAME ) ;
1212 lprc->bottom -= GetSystemMetrics( SM_CYFRAME ) ;
1213 }
1214 else
1215 if (TestWinStyle( hWnd, DS_MODALFRAME )) // if it's a dialog box
1216 {
1217 lprc->left += GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ;
1218 lprc->top += GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ;
1219 lprc->right -= GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ;
1220 lprc->bottom -= GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ;
1221 }
1222 else
1223 if (TestWinStyle( hWnd, WS_BORDER ))
1224 {
1225 lprc->left += GetSystemMetrics( SM_CXBORDER ) ;
1226 lprc->top += GetSystemMetrics( SM_CYBORDER ) ;
1227 lprc->right -= GetSystemMetrics( SM_CXBORDER ) ;
1228 lprc->bottom -= GetSystemMetrics( SM_CYBORDER ) ;
1229 }
1230
1231 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1232 lprc->right = lprc->left + nCapSize ;
1233 else
1234 lprc->bottom = lprc->top + nCapSize ;
1235
1236 return TRUE ;
1237 } // GetCaptionRect()
1238
1239 // GetIconRect( HWND hWnd, LPRECT lprc )
1240 //
1241 // Calculates the rect of the icon in screen coordinates.
1242 //
1243 BOOL PASCAL GetIconRect( HWND hWnd, LPRECT lprc )
1244 {
1245 UINT nCapSize ;
1246 BOOL fMenu, fVert ;
1247
1248 fMenu= TestWinStyle( hWnd, WS_SYSMENU ) ;
1249 fVert = TestWinStyle( hWnd, IBS_VERTCAPTION ) ;
1250
1251 if (!GetCaptionRect( hWnd, lprc )) // window coords
1252 return FALSE ;
1253
1254 if (!fMenu)
1255 {
1256 SetRectEmpty( lprc ) ;
1257 return FALSE ;
1258 }
1259
1260 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1261
1262 if (fVert)
1263 lprc->bottom = lprc->top + nCapSize ;
1264 else
1265 lprc->right = lprc->left + nCapSize ;
1266
1267 lprc->bottom-- ;
1268 lprc->right-- ;
1269
1270 return TRUE ;
1271
1272 } // GetIconRect()
1273
1274 // GetMinButtonRect()
1275 //
1276 // Calculates the rect of the minimize button in screen
1277 // coordinates.
1278 //
1279 // For horizontal captions, we have the following situation ('Y' is minimize
1280 // and '^' is maximize or restore):
1281 //
1282 // +---------------------------------+
1283 // | - | | Y | ^ |
1284 // +---------------------------------+
1285 // | |.......| <-- This is the width (nSize)
1286 //
1287 // For vertical captions, we have the following:
1288 //
1289 // | |
1290 // | |
1291 // | |
1292 // | |
1293 // | |
1294 // | |
1295 // |--|--
1296 // | Y| .
1297 // |--| . <-- This is the height of the rectangle (nSize)
1298 // | ^| .
1299 // +--+--
1300 //
1301 // In order to figure out where the minimize button goes, we first need
1302 // to know if there is a maximize button. If so, use GetMaxButtonRect()
1303 // to place...
1304 //
1305 BOOL PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc )
1306 {
1307 if (!TestWinStyle( hWnd, WS_MINIMIZEBOX ))
1308 {
1309 SetRectEmpty( lprc ) ;
1310 return FALSE ;
1311 }
1312
1313 // The minimize button can be in either position 1 or 2. If there
1314 // is a maximize button, it's in position 2.
1315 //
1316 if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ))
1317 return GetButtonRect( hWnd, 2, lprc ) ;
1318 else
1319 return GetButtonRect( hWnd, 1, lprc ) ;
1320 }
1321
1322 // GetMaxButtonRect()
1323 //
1324 // Calculates the rect of the maximize button in screen
1325 // coordinates.
1326 //
1327 // The maximize button, if present, is always to the far right
1328 // or bottom.
1329 //
1330 BOOL PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc )
1331 {
1332 //The maximize button can only be in position 1.
1333 //
1334 if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ))
1335 return GetButtonRect( hWnd, 1, lprc ) ;
1336 else
1337 {
1338 SetRectEmpty( lprc ) ;
1339 return FALSE ;
1340 }
1341 }
1342
1343 // Get the rect where a button would go.
1344 //
1345 // This function does not care if it's a min or max, just whether
1346 // it is the first from the right/bottom or second from the right/bottom
1347 // and so on..
1348 //
1349 BOOL PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc )
1350 {
1351 UINT nSize = 0 ;
1352
1353 if (!GetCaptionRect( hWnd, lprc )) //window coords
1354 return FALSE ;
1355
1356 nSize = GETCAPTIONSIZE( hWnd ) ;
1357
1358 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1359 {
1360 lprc->bottom -= nSize * (nPos-1) ;
1361 lprc->top = lprc->bottom - nSize + 1 ;
1362 }
1363 else
1364 {
1365 lprc->right -= nSize * (nPos-1) ;
1366 lprc->left = lprc->right - nSize + 1 ;
1367 }
1368
1369 return TRUE ;
1370 } // GetButtonRect()
1371
1372 // DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed )
1373 //
1374 // Draws either the min, max, or restore buttons. If fMin is FALSE then it
1375 // will draw either the Max or Restore button. If fDepressed is TRUE it will
1376 // draw the button in a down state.
1377 //
1378 void PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed)
1379 {
1380 RECT rcButton ;
1381 RECT rc ;
1382 COLORREF rgbWindowFrame ;
1383 BOOL fDC ;
1384 UINT nCapSize ;
1385 UINT nOffset ;
1386 int n ;
1387
1388 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1389
1390 // If you look at the standard Windows' min/max buttons, you will notice
1391 // that they have two pixels of 'shadow' to the bottom and right. Since
1392 // our buttons can be really, really small, we only want one pixel of
1393 // shadow when they are small. I arbitrarily decided that if the
1394 // caption size is greater than or equal to 20 we will use two
1395 // pixels. That's what this THREASHOLD stuff does.
1396 //
1397 #define THRESHOLD 20
1398 nOffset = (nCapSize >= THRESHOLD) ? 2 : 1 ;
1399
1400 if (!hDC)
1401 {
1402 fDC = TRUE ;
1403 hDC = GetWindowDC( hWnd ) ;
1404 }
1405 else
1406 fDC = FALSE ;
1407
1408 if (hDC)
1409 {
1410 rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
1411
1412 if (fMin)
1413 GetMinButtonRect( hWnd, &rcButton ) ;
1414 else
1415 GetMaxButtonRect( hWnd, &rcButton ) ;
1416
1417 GetWindowRect( hWnd, &rc ) ;
1418 OffsetRect( &rcButton, -rc.left, -rc.top ) ;
1419
1420 rc = rcButton ;
1421 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1422 {
1423 rc = rcButton ; //separator line
1424 rc.bottom = --rc.top + 1 ;
1425 rcButton.right-- ;
1426 }
1427 else
1428 {
1429 rc = rcButton ; //separator line
1430 rc.right = --rc.left + 1 ;
1431 rcButton.bottom-- ;
1432 }
1433
1434 //Draw separator line
1435 SetBkColor( hDC, rgbWindowFrame ) ;
1436 DRAWFASTRECT( hDC, &rc ) ;
1437
1438 //Fill
1439 SetBkColor( hDC, RGBLTGRAY ) ;
1440 DRAWFASTRECT( hDC, &rcButton ) ;
1441
1442 if (!fDepressed)
1443 {
1444 //The normal min/max buttons have one pixel on the top and left
1445 //sides for the highlight, and two pixels on the bottom and
1446 //right side for the shadow.
1447 //
1448 //When our caption is 'small' we only use one pixel on all
1449 //sides.
1450 //
1451 SetBkColor( hDC, RGBWHITE ) ;
1452 //Draw left side
1453 rc = rcButton ;
1454 rc.right = rc.left + 1 ;
1455 DRAWFASTRECT( hDC, &rc ) ;
1456
1457 //Draw Top
1458 rc = rcButton ;
1459 rc.bottom = rc.top + 1 ;
1460 DRAWFASTRECT( hDC, &rc ) ;
1461
1462 SetBkColor( hDC, RGBGRAY ) ;
1463 //Draw right side
1464 rc = rcButton ;
1465 rc.left = rc.right - 1 ;
1466 DRAWFASTRECT( hDC, &rc ) ;
1467 if (nCapSize > THRESHOLD)
1468 {
1469 rc.left-- ;
1470 rc.top++ ;
1471 DRAWFASTRECT( hDC, &rc ) ;
1472 }
1473
1474 //Draw bottom
1475 rc = rcButton ;
1476 rc.top = rc.bottom - 1 ;
1477 DRAWFASTRECT( hDC, &rc ) ;
1478 if (nCapSize > THRESHOLD)
1479 {
1480 rc.top-- ;
1481 rc.left++ ;
1482 DRAWFASTRECT( hDC, &rc ) ;
1483 }
1484
1485 rcButton.left++ ;
1486 rcButton.top++ ;
1487 rcButton.right -= nOffset ;
1488 rcButton.bottom -= nOffset ;
1489 }
1490 else
1491 {
1492 //Draw depressed state
1493
1494 SetBkColor( hDC, RGBGRAY ) ;
1495 //Draw left side
1496 rc = rcButton ;
1497 rc.right = rc.left + nOffset ;
1498 DRAWFASTRECT( hDC, &rc ) ;
1499
1500 //Draw Top
1501 rc = rcButton ;
1502 rc.bottom = rc.top + nOffset ;
1503 DRAWFASTRECT( hDC, &rc ) ;
1504
1505 rcButton.left += 2 * nOffset ;
1506 rcButton.top += 2 * nOffset ;
1507 }
1508
1509 // Now draw the arrows. We do not want the
1510 // arrows to grow too large when we have a bigger than
1511 // normal caption, so we restrict their size.
1512 //
1513 // rcButton now represents where we can place our
1514 // arrows.
1515 //
1516 // The maximum size of our arrows (i.e. the width of rcButton)
1517 // has been empirically determined to be SM_CYCAPTION / 2
1518 //
1519 n = ((GetSystemMetrics( SM_CYCAPTION )) / 2) -
1520 (rcButton.right - rcButton.left) ;
1521 if (n < 1)
1522 InflateRect( &rcButton, n/2-1, n/2-1 ) ;
1523
1524 if (fMin)
1525 DrawArrow( hDC, &rcButton, ARROW_DOWN ) ;
1526 else
1527 if (IsZoomed( hWnd ))
1528 {
1529 DrawArrow( hDC, &rcButton, ARROW_RESTORE ) ;
1530 }
1531 else
1532 DrawArrow( hDC, &rcButton, ARROW_UP ) ;
1533
1534 if (fDC)
1535 ReleaseDC( hWnd, hDC ) ;
1536 }
1537
1538 } // DrawButton()
1539
1540
1541 // DrawArrow
1542 //
1543 // Draws either a up or down arrow. The arrow is bound by the rectangle
1544 //
1545 void PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle )
1546 {
1547 int row ;
1548 int xTip ;
1549 int yTip ;
1550 RECT rc ;
1551 int nMax = (lprc->bottom - lprc->top) >> 1 ;
1552
1553 SetBkColor( hdc, RGBBLACK ) ;
1554
1555 // We draw the arrow by drawing a series of horizontal lines
1556 //
1557 xTip = lprc->left + ((lprc->right - lprc->left+1) >> 1) ;
1558 switch (uiStyle)
1559 {
1560 case ARROW_UP:
1561 yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 2) ;
1562 for (row = 1 ; row <= nMax ; row++ )
1563 {
1564 rc.left = xTip - row ;
1565 rc.right = xTip + row - 1 ;
1566 rc.top = yTip + row ;
1567 rc.bottom = rc.top + 1 ;
1568 DRAWFASTRECT( hdc, &rc ) ;
1569 }
1570 break ;
1571
1572 case ARROW_DOWN:
1573 yTip = lprc->bottom - ((lprc->bottom - lprc->top-1) >> 2) ;
1574 for ( row = nMax ; row > 0 ; row-- )
1575 {
1576 rc.left = xTip - row ;
1577 rc.right = xTip + row - 1 ;
1578 rc.top = yTip - row ;
1579 rc.bottom = rc.top + 1 ;
1580 DRAWFASTRECT( hdc, &rc ) ;
1581 }
1582 break ;
1583
1584 case ARROW_RESTORE:
1585 default:
1586 yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 3) - 2;
1587 for (row = 1 ; row <= nMax ; row++ )
1588 {
1589 rc.left = xTip - row ;
1590 rc.right = xTip + row - 1 ;
1591 rc.top = yTip + row ;
1592 rc.bottom = rc.top + 1 ;
1593 DRAWFASTRECT( hdc, &rc ) ;
1594 }
1595
1596 yTip += (nMax+1) * 2 ;
1597 for ( row = nMax ; row > 0 ; row-- )
1598 {
1599 rc.left = xTip - row ;
1600 rc.right = xTip + row - 1 ;
1601 rc.top = yTip - row ;
1602 rc.bottom = rc.top + 1 ;
1603 DRAWFASTRECT( hdc, &rc ) ;
1604 }
1605 break ;
1606 }
1607
1608 } // DrawArrow()
1609
1610 #endif // wxUSE_ITSY_BITSY