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