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