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