]> git.saurik.com Git - wxWidgets.git/blob - src/msw/minifram.cpp
SelectItem() always sends the notification messages
[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 USE_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 (FARPROC) 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 USE_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 USE_EXTTEXTOUT
187 #ifdef USE_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
380 if (TestWinStyle(hWnd, WS_BORDER ))
381 {
382 cx = GetSystemMetrics( SM_CXBORDER ) ;
383 cy = GetSystemMetrics( SM_CYBORDER ) ;
384 }
385
386 GetIconRect( hWnd, &rcMenu ) ;
387 GetMinButtonRect( hWnd, &rcMin ) ;
388 GetMaxButtonRect( hWnd, &rcMax ) ;
389 nX = (rcMenu.right-rcMenu.left) +
390 (rcMin.right-rcMin.left) +
391 (rcMin.right-rcMin.left) ;
392
393
394 if (TestWinStyle( hWnd, IBS_VERTCAPTION ) )
395 {
396 lppt[3].x = nCapSize + cx * 2 - 1 ;
397 lppt[3].y = nX + (2* nCapSize) ;
398 }
399 else
400 {
401 lppt[3].x = nX + (2* nCapSize) ;
402 lppt[3].y = nCapSize + cy * 2 - 1 ;
403 }
404 }
405 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
406 }
407 break ;
408
409 /////////////////////////////////////////////////////////////////////
410 // Non-client area messages. These are used to allow the
411 // minature caption bar to be handled correctly.
412 //
413 case WM_NCCREATE:
414 {
415 DWORD dwStyle ;
416
417 // We have two things that we need to store somewhere:
418 // 1) The caption height (width).
419 // and 2) A flag indicating whether the sysmenu was
420 // just up or not.
421 //
422 // CAPTIONXY is a macro that calls GetSystemMetrics.
423 //
424 SETCAPTIONSIZE( hWnd, CAPTIONXY ) ;
425
426 // Set our flag that tells us whether the system menu was
427 // 'just up'.
428 //
429 SETMENUWASUPFLAG( hWnd, FALSE ) ;
430
431 // Are we in 3.1? If so we have some neat features
432 // we can use like rotated TrueType fonts.
433 //
434 fWin31 = (BOOL)(LOWORD( GetVersion() ) >= 0x030A) ;
435
436 // If IBS_????CAPTION was specified and the WS_DLGFRAME (or
437 // WS_DLGFRAME 'cause it == WS_CAPTION | WS_BORDER)
438 // was specified the creator made a mistake. Things get really
439 // ugly if DefWindowProc sees WS_DLGFRAME, so we strip
440 // the WS_DLGFRAME part off!
441 //
442 dwStyle = GetWindowLong( hWnd, GWL_STYLE ) ;
443 if ((dwStyle & IBS_VERTCAPTION || dwStyle & IBS_HORZCAPTION) &&
444 dwStyle & WS_DLGFRAME)
445 {
446 dwStyle &= (DWORD)~WS_DLGFRAME ;
447 SetWindowLong( hWnd, GWL_STYLE, dwStyle ) ;
448 }
449 }
450 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
451
452 case WM_NCDESTROY:
453 // We store the caption size in a window prop. so we
454 // must remove props.
455 //
456 FREECAPTIONSIZE( hWnd ) ;
457 FREEMENUWASUPFLAG( hWnd ) ;
458 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
459
460 case WM_NCCALCSIZE:
461 // This is sent when the window manager wants to find out
462 // how big our client area is to be. If we have a mini-caption
463 // then we trap this message and calculate the cleint area rect,
464 // which is the client area rect calculated by DefWindowProc()
465 // minus the width/height of the mini-caption bar
466 //
467 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
468 if (!IsIconic( hWnd ) && HASCAPTION( hWnd ))
469 {
470 nCapSize = GETCAPTIONSIZE( hWnd ) ;
471
472 if (TestWinStyle( hWnd, IBS_VERTCAPTION ) )
473 ((LPRECT)lParam)->left += nCapSize ;
474 else
475 ((LPRECT)lParam)->top += nCapSize ;
476 }
477 return lRet ;
478
479 case WM_NCHITTEST:
480 // This message is sent whenever the mouse moves over us.
481 // We will depend on DefWindowProc for everything unless
482 // there is a mini-caption, in which case we will
483 // return HTCAPTION or HTSYSMENU. When the user clicks
484 // or double clicks, NC_LBUTTON/ message are sent with
485 // wParam equal to what we return here.
486 // This means that this is an ideal place to figure out
487 // where we are!
488 //
489 // let defwindowproc handle the standard borders etc...
490 //
491 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
492 if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && lRet == HTNOWHERE)
493 {
494 RECT rc ;
495 RECT rcMenu ;
496 RECT rcMinButton ;
497 RECT rcMaxButton ;
498 POINT pt ;
499
500 nCapSize = GETCAPTIONSIZE( hWnd ) ;
501
502 // if DefWindowProc returned HTCAPTION then we have to
503 // refine the area and return HTSYSMENU if appropriate
504 //
505 pt.x = LOWORD( lParam ) ;
506 pt.y = HIWORD( lParam ) ;
507
508 GetCaptionRect( hWnd, &rc ) ; // window coords
509 if (PtInRect( &rc, pt ))
510 {
511 lRet = HTCAPTION ;
512
513 // rely on the fact that Get???Rect() return an invalid
514 // (empty) rectangle if the menu/buttons don't exist
515 //
516 GetIconRect( hWnd, &rcMenu ) ;
517 GetMinButtonRect( hWnd, &rcMinButton ) ;
518 GetMaxButtonRect( hWnd, &rcMaxButton ) ;
519
520 if (PtInRect( &rcMenu, pt ))
521 lRet = HTSYSMENU ;
522
523 if (PtInRect( &rcMinButton, pt ))
524 lRet = HTMINBUTTON ;
525 else
526 if (PtInRect( &rcMaxButton, pt ))
527 lRet = HTMAXBUTTON ;
528 }
529 }
530 if (lRet != HTSYSMENU)
531 SETMENUWASUPFLAG( hWnd, FALSE ) ;
532 return lRet ;
533
534 case WM_NCLBUTTONDBLCLK:
535 // Windows recieve WM_NC?BUTTONDBLCLK messages whether they
536 // have CS_DBLCLKS or not. We watch for one of these
537 // to see if the user double clicked on the system menu (to
538 // close the window) or on the caption (to maximize the window).
539 //
540 if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && wParam == HTSYSMENU)
541 {
542 SendMessage( hWnd, WM_CLOSE, 0, 0L ) ;
543 break ;
544 }
545 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
546
547 case WM_NCLBUTTONDOWN:
548 {
549 RECT rc ;
550
551 // If we're iconic or we don't have a caption then
552 // DefWindowProc will do the job just fine.
553 //
554 if (IsIconic( hWnd ) || !HASCAPTION( hWnd ))
555 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
556
557 // Here's were we handle the system menu, the min and max buttons.
558 // If you wanted to change the behavior of the min/max buttons
559 // do something like swap tool palettes or something, you
560 // would change the SendMessage() calls below.
561 //
562 switch (wParam)
563 {
564 case HTSYSMENU:
565 if (GETMENUWASUPFLAG( hWnd ) == FALSE && DoMenu( hWnd ))
566 SETMENUWASUPFLAG( hWnd, TRUE ) ;
567 else
568 SETMENUWASUPFLAG( hWnd, FALSE ) ;
569 break ;
570
571 case HTMINBUTTON:
572 GetMinButtonRect( hWnd, &rc ) ;
573 // Note that DepressMinMaxButton() goes into
574 // a PeekMessage() loop waiting for the mouse
575 // to come back up.
576 //
577 if (DepressMinMaxButton( hWnd, wParam, &rc ))
578 SendMessage( hWnd, WM_SYSCOMMAND, SC_MINIMIZE, lParam ) ;
579 break ;
580
581 case HTMAXBUTTON:
582 GetMaxButtonRect( 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 {
589 if (IsZoomed(hWnd))
590 SendMessage( hWnd, WM_SYSCOMMAND, SC_RESTORE, lParam ) ;
591 else
592 SendMessage( hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, lParam ) ;
593 }
594 break ;
595
596 default:
597 // Well, it appears as though the user clicked somewhere other
598 // than the buttons. We let DefWindowProc do it's magic.
599 // This is where things like dragging and sizing the
600 // window happen.
601 //
602 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
603 }
604 }
605 break ;
606
607 case WM_NCPAINT:
608 case WM_NCACTIVATE:
609 if (IsIconic( hWnd ))
610 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
611
612 // Paint the non-client area here. We will call DefWindowProc
613 // after we are done so it can paint the borders and so
614 // forth...
615 //
616 lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
617 if (HASCAPTION( hWnd ))
618 {
619 RECT rcCap ;
620 RECT rc ;
621 HDC hDC = GetWindowDC( hWnd ) ;
622 BOOL fActive ;
623
624 GetCaptionRect( hWnd, &rcCap ) ; // Convert to window coords
625 GetWindowRect( hWnd, &rc ) ;
626 OffsetRect( &rcCap, -rc.left, -rc.top ) ;
627
628 if (uiMsg == WM_NCPAINT)
629 fActive = (hWnd == GetActiveWindow()) ;
630 else
631 fActive = wParam ;
632
633 DrawCaption( hDC, hWnd, &rcCap,
634 TestWinStyle(hWnd, IBS_VERTCAPTION),
635 TestWinStyle(hWnd, WS_SYSMENU),
636 TestWinStyle(hWnd, WS_MINIMIZEBOX),
637 TestWinStyle(hWnd, WS_MAXIMIZEBOX),
638 fActive ) ;
639
640 ReleaseDC( hWnd, hDC ) ;
641 }
642 return lRet;
643 break;
644
645 default:
646 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
647 }
648
649 return 0L ;
650
651 } // ibDefWindowProc()
652
653 // ibAdjustWindowRect( HWND hWnd, LPRECT lprc )
654 //
655 // Does the same thing as the USER function AdjustWindowRect(),
656 // but knows about itsybitsy windows. AdjustWindowRect() is
657 // bogus for stuff like this.
658 //
659 void WINAPI ibAdjustWindowRect( HWND hWnd, LPRECT lprc )
660 {
661 short cx = 0, cy = 0 ;
662 UINT nCapSize ;
663
664 nCapSize = GETCAPTIONSIZE( hWnd ) ;
665
666 // First check Windows's styles, then our own.
667 //
668 if (TestWinStyle( hWnd, WS_THICKFRAME ))
669 {
670 cx = GetSystemMetrics( SM_CXFRAME ) ;
671 cy = GetSystemMetrics( SM_CYFRAME ) ;
672 }
673 else
674 if (TestWinStyle(hWnd, DS_MODALFRAME ))
675 {
676 cx = GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ;
677 cy = GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ;
678 }
679 else
680 if (TestWinStyle(hWnd, WS_BORDER ))
681 {
682 cx = GetSystemMetrics( SM_CXBORDER ) ;
683 cy = GetSystemMetrics( SM_CYBORDER ) ;
684 }
685
686 InflateRect( lprc, cx, cy ) ;
687
688 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
689 lprc->left -= nCapSize ;
690 else
691 if (TestWinStyle( hWnd, IBS_HORZCAPTION ))
692 lprc->top -= nCapSize ;
693
694 } // ibAdjustWindowRect()
695
696
697 ///////////////////////////////////////////////////////////////////////
698 // Internal functions
699 ///////////////////////////////////////////////////////////////////////
700
701 // DepressMinMaxButton()
702 //
703 // This function is called when the user has pressed either the min or
704 // max button (i.e. WM_NCLBUTTONDOWN). We go into a Peekmessage() loop,
705 // waiting for the mouse to come back up. This allows us to make the
706 // button change up/down state like a real button does.
707 //
708 // lprc points to the rectangle that describes the button the
709 // user has clicked on.
710 //
711 BOOL PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT lprc )
712 {
713 BOOL fDepressed = TRUE ;
714 MSG msg ;
715
716 // Draw button in down state
717 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed ) ;
718 SetCapture( hWnd ) ;
719
720 while (TRUE)
721 {
722 if (PeekMessage((LPMSG)&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
723 {
724 switch (msg.message)
725 {
726 case WM_LBUTTONUP:
727 if (fDepressed)
728 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, !fDepressed ) ;
729 ReleaseCapture();
730 return PtInRect( lprc, msg.pt ) ;
731
732 case WM_MOUSEMOVE:
733 if (PtInRect( lprc, msg.pt ))
734 {
735 if (!fDepressed)
736 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = TRUE ) ;
737 }
738 else
739 {
740 if (fDepressed)
741 DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = FALSE ) ;
742 }
743 break;
744 }
745 }
746 }
747
748 } // DepressMinMaxButton()
749
750 // DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
751 // BOOL fVert, BOOL fSysMenu, BOOL fActive )
752 //
753 // This function draws an itsy bitsy caption bar with or
754 // without system menu to the dc specified by hDC. The
755 // caption is drawn to fit within the lprc RECT and is
756 // drawn//withOut/ borders.
757 //
758 BOOL PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
759 BOOL fVert, BOOL fSysMenu, BOOL fMin,
760 BOOL fMax, BOOL fActive )
761 {
762 RECT rc ;
763 RECT rcCap ;
764 COLORREF rgbCaptionBG ;
765 COLORREF rgbText ;
766 COLORREF rgbWindowFrame ;
767 HBRUSH hbrCaption ;
768 UINT ui ;
769 UINT nCapSize ;
770
771 nCapSize = GETCAPTIONSIZE( hWnd ) ;
772
773 // Get the colors.
774 //
775 rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
776
777 // if we have focus use the active caption color
778 // otherwise use the inactive caption color
779 //
780 if (fActive)
781 {
782 rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ;
783 rgbCaptionBG = GetSysColor( COLOR_ACTIVECAPTION ) ;
784 }
785 else
786 {
787 if (fWin31)
788 rgbText = GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ;
789 else
790 rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ;
791
792 rgbCaptionBG = GetSysColor( COLOR_INACTIVECAPTION ) ;
793 }
794
795 SetBkMode( hDC, TRANSPARENT ) ;
796 SelectObject( hDC, GetStockObject( NULL_BRUSH ) ) ;
797 SelectObject( hDC, GetStockObject( NULL_PEN ) ) ;
798
799 rcCap = *lprc ;
800
801 if (fSysMenu)
802 {
803 if (fVert)
804 rcCap.top += nCapSize ;
805 else
806 rcCap.left += nCapSize ;
807 }
808
809 if (fMax)
810 {
811 if (fVert)
812 rcCap.bottom -= nCapSize ;
813 else
814 rcCap.right -= nCapSize ;
815 }
816
817 if (fMin)
818 {
819 if (fVert)
820 rcCap.bottom -= nCapSize ;
821 else
822 rcCap.right -= nCapSize ;
823 }
824
825 if (fVert)
826 {
827 rc.left = lprc->right - 1 ;
828 rc.right = lprc->right ;
829 rc.top = lprc->top ;
830 rc.bottom = lprc->bottom ;
831 }
832 else
833 {
834 rc.left = lprc->left ;
835 rc.right = lprc->right ;
836 rc.bottom = lprc->bottom ;
837 rc.top = rc.bottom - 1 ;
838 }
839
840 SetBkColor( hDC, rgbWindowFrame ) ;
841 DRAWFASTRECT( hDC, &rc ) ;
842
843 hbrCaption = CreateSolidBrush( rgbCaptionBG ) ;
844 hbrCaption = (HBRUSH) SelectObject( hDC, hbrCaption ) ;
845 SelectObject( hDC, (HPEN) GetStockObject( NULL_PEN ) ) ;
846 if (fVert)
847 Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right, rcCap.bottom + 1 ) ;
848 else
849 Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right+1, rcCap.bottom ) ;
850 hbrCaption = (HBRUSH) SelectObject( hDC, hbrCaption ) ;
851 DeleteObject( hbrCaption ) ;
852
853
854 // Draw caption text here. Only do it in 3.1 'cause 3.1 gives
855 // us 'small fonts'.
856 //
857 ui = GetWindowTextLength( hWnd ) ;
858 if (fWin31)
859 {
860 HFONT hFont ;
861 LPSTR lpsz ;
862 LOGFONT lf ;
863 TEXTMETRIC tm ;
864 int cx ;
865 int cy ;
866 SIZE Size ;
867
868 if ((lpsz = (char*)GlobalAllocPtr( GHND, ui + 2 )))
869 {
870 UINT nBkMode ;
871
872 GetWindowText( hWnd, lpsz, ui + 1 ) ;
873 nBkMode = SetBkMode( hDC, TRANSPARENT ) ;
874 rgbText = SetTextColor( hDC, rgbText ) ;
875
876 memset( &lf, '\0', sizeof(LOGFONT) ) ;
877
878 lf.lfHeight = -(int)(nCapSize - 3) ;
879 lf.lfCharSet = ANSI_CHARSET ;
880 lf.lfQuality = DEFAULT_QUALITY ;
881 lf.lfClipPrecision = CLIP_LH_ANGLES | CLIP_STROKE_PRECIS ;
882 if (nCapSize >= 20)
883 {
884 lf.lfWeight = FW_BOLD ;
885 }
886
887 if (fVert)
888 {
889 // Can only rotate true type fonts (well, ok, we could
890 // try and use "modern").
891 strcpy( lf.lfFaceName, "Arial" ) ;
892 lf.lfPitchAndFamily = FF_SWISS | 0x04;
893 lf.lfEscapement = 900 ;
894
895 // Note: The Win 3.1 documentation for CreateFont() say's
896 // that the lfOrientation member is ignored. It appears,
897 // that on Windows 16 3.1 this is true, but when running
898 // as a 16 bit WinApp on WindowsNT 3.1 the lfOrientation
899 // must be set or the text does not rotate!
900 //
901 lf.lfOrientation = 900 ;
902
903 hFont = CreateFontIndirect( &lf ) ;
904 hFont = (HFONT) SelectObject( hDC, hFont ) ;
905
906 GetTextExtentPoint( hDC, lpsz, ui, &Size ) ;
907 cx = rcCap.bottom - ((rcCap.bottom - rcCap.top - Size.cx) / 2) ;
908 cy = rcCap.left - 1 + ((rcCap.right - rcCap.left - Size.cy) / 2) ;
909
910 // Make sure we got a rotatable font back.
911 //
912 GetTextMetrics( hDC, &tm ) ;
913 if (tm.tmPitchAndFamily & TMPF_VECTOR ||
914 tm.tmPitchAndFamily & TMPF_TRUETYPE)
915 {
916 ExtTextOut( hDC,
917 cy,
918 min( (long)cx, rcCap.bottom),
919 ETO_CLIPPED, &rcCap,
920 lpsz, ui, NULL ) ;
921 }
922
923 hFont = (HFONT) SelectObject( hDC, hFont ) ;
924 DeleteObject( hFont ) ;
925 }
926 else
927 {
928 // Use small fonts always for the horizontal. Cause it looks
929 // more like "System" than Arial.
930 //
931 lf.lfPitchAndFamily = FF_SWISS ;
932
933 hFont = CreateFontIndirect( &lf ) ;
934 hFont = (HFONT) SelectObject( hDC, hFont ) ;
935
936 GetTextExtentPoint( hDC, lpsz, ui, &Size ) ;
937 cx = rcCap.left + ((rcCap.right - rcCap.left - Size.cx) / 2) ;
938 cy = rcCap.top + ((rcCap.bottom - rcCap.top - Size.cy) / 2) ;
939
940 // Figger out how big the string is
941 //
942 ExtTextOut( hDC,
943 max( (long)cx, rcCap.left ),
944 cy,
945 ETO_CLIPPED, &rcCap,
946 lpsz, ui, NULL ) ;
947
948 hFont = (HFONT) SelectObject( hDC, hFont ) ;
949 DeleteObject( hFont ) ;
950 }
951
952 // Unsetup the DC
953 //
954 rgbText = SetTextColor( hDC, rgbText ) ;
955 SetBkMode( hDC, nBkMode ) ;
956
957 GlobalFreePtr( lpsz ) ;
958 }
959 }
960
961 if (fSysMenu)
962 DrawSysMenu( hDC, hWnd, FALSE ) ;
963
964 if (fMin)
965 DrawButton( hDC, hWnd, TRUE, FALSE ) ;
966
967 if (fMax)
968 DrawButton( hDC, hWnd, FALSE, FALSE ) ;
969
970 return TRUE ;
971
972 } // DrawCaption()
973
974
975 // DrawSysMenu( HDC hDC, hWnd, BOOL fInvert )
976 //
977 // Draws the little system menu icon.
978 //
979 void PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert )
980 {
981 RECT rcIcon ;
982 RECT rcTemp ;
983 RECT rc ;
984 COLORREF rgbIconFace ;
985 COLORREF rgbWindowFrame ;
986 BOOL fDC ;
987 UINT nCapSize ;
988
989 nCapSize = GETCAPTIONSIZE( hWnd ) ;
990
991 if (!hDC)
992 {
993 fDC = TRUE ;
994 hDC = GetWindowDC( hWnd ) ;
995 }
996 else
997 fDC = FALSE ;
998
999 if (hDC)
1000 {
1001 rgbIconFace = GetNearestColor( hDC, RGBLTGRAY ) ;
1002 rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
1003
1004 GetIconRect( hWnd, &rcIcon ) ;
1005 GetWindowRect( hWnd, &rc ) ;
1006
1007 OffsetRect( &rcIcon, -rc.left, -rc.top ) ;
1008
1009 rcTemp = rcIcon ;
1010
1011 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1012 {
1013 rc = rcIcon ; // separator line
1014 rc.top = ++rc.bottom - 1 ;
1015 }
1016 else
1017 {
1018 rc = rcIcon ; // separator line
1019 rc.left = ++rc.right - 1 ;
1020 }
1021
1022 // Fill
1023 SetBkColor( hDC, rgbIconFace ) ;
1024 DRAWFASTRECT( hDC, &rcTemp ) ;
1025
1026 // Draw separator line
1027 SetBkColor( hDC, rgbWindowFrame ) ;
1028 DRAWFASTRECT( hDC, &rc ) ;
1029
1030 if (nCapSize > 4)
1031 {
1032 // Draw the little horizontal doo-hickey
1033 //
1034 rcTemp.top = rcIcon.top + ((nCapSize-1) / 2) ;
1035 rcTemp.bottom = rcTemp.top + 3 ;
1036 rcTemp.left = rcTemp.left + 3 ;
1037 rcTemp.right = rcTemp.right - 1 ;
1038
1039 SetBkColor( hDC, RGBGRAY ) ;
1040 DRAWFASTRECT( hDC, &rcTemp ) ;
1041
1042 rc = rcTemp ;
1043 OffsetRect( &rc, -1, -1 ) ;
1044 SetBkColor( hDC, RGBBLACK ) ;
1045 DRAWFASTRECT( hDC, &rc ) ;
1046
1047 InflateRect( &rc, -1, -1 ) ;
1048 SetBkColor( hDC, RGBWHITE ) ;
1049 DRAWFASTRECT( hDC, &rc ) ;
1050 }
1051
1052 if (fInvert)
1053 InvertRect( hDC, &rcIcon ) ;
1054
1055 if (fDC)
1056 ReleaseDC( hWnd, hDC ) ;
1057 }
1058
1059 } // DrawSysMenu()
1060
1061 // DoMenu( HWND hWnd )
1062 //
1063 // Pops up the system menu.
1064 //
1065 BOOL PASCAL DoMenu( HWND hWnd )
1066 {
1067 HDC hDC ;
1068 RECT rcIcon ;
1069 RECT rc ;
1070 POINT pt ;
1071 HMENU hMenu ;
1072 DWORD dw ;
1073
1074 if (!TestWinStyle(hWnd, WS_SYSMENU))
1075 return FALSE ;
1076
1077 if ((hDC = GetWindowDC( hWnd )))
1078 {
1079 // Invert the icon
1080 //
1081 DrawSysMenu( hDC, hWnd, TRUE ) ;
1082
1083 // Pop up the menu
1084 //
1085 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1086 {
1087 pt.x = -1 ;
1088 pt.y = 0 ;
1089 }
1090 else
1091 {
1092 pt.x = 0 ;
1093 pt.y = -1 ;
1094 }
1095
1096 GetIconRect( hWnd, &rcIcon ) ;
1097 GetWindowRect( hWnd, &rc ) ;
1098 OffsetRect( &rcIcon, -rc.left, -rc.top ) ;
1099
1100 ClientToScreen( hWnd, &pt ) ;
1101 ClientToScreen( hWnd, (LPPOINT)&rc.right ) ;
1102
1103 dw = GetWindowLong( hWnd, GWL_STYLE ) ;
1104 SetWindowLong( hWnd, GWL_STYLE, dw | WS_SYSMENU ) ;
1105
1106 hMenu = GetSystemMenu( hWnd, FALSE ) ;
1107 SetupSystemMenu( hWnd, hMenu ) ;
1108
1109 SetWindowLong( hWnd, GWL_STYLE, dw ) ;
1110
1111 TrackPopupMenu( hMenu, 0, //TPM_LEFTALIGN,
1112 pt.x,
1113 pt.y,
1114 0,
1115 hWnd,
1116 &rc ) ;
1117
1118 DrawSysMenu( hDC, hWnd, FALSE ) ;
1119 ReleaseDC( hWnd, hDC ) ;
1120 }
1121 return TRUE ;
1122
1123 } // DoMenu()
1124
1125 // SetupSystemMenu( HWND hWnd, HMENU hMenu )
1126 //
1127 // Enables/Disables the appropriate menu items on the
1128 // menu passed for the window passed.
1129 //
1130 void PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu )
1131 {
1132 UINT wMove ;
1133 UINT wSize ;
1134 UINT wMinBox ;
1135 UINT wMaxBox ;
1136 UINT wRestore ;
1137
1138 // Assume all should be grayed.
1139 //
1140 wSize = wMove = wMinBox = wMaxBox = wRestore = MF_GRAYED ;
1141
1142 if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ) || IsIconic( hWnd ))
1143 wMaxBox = MF_ENABLED ;
1144
1145 if (TestWinStyle( hWnd, WS_MINIMIZEBOX ))
1146 wMinBox = MF_ENABLED ;
1147
1148 if (IsZoomed( hWnd ))
1149 wRestore = MF_ENABLED ;
1150
1151 if (TestWinStyle( hWnd, WS_THICKFRAME ) &&
1152 !(IsIconic( hWnd ) || IsZoomed( hWnd )))
1153 wSize = MF_ENABLED ;
1154
1155 if (!IsZoomed( hWnd ) &&
1156 !IsIconic( hWnd ) &&
1157 TestWinStyle( hWnd, WS_CAPTION ) )
1158 wMove = MF_ENABLED ;
1159
1160 EnableMenuItem( hMenu, SC_MOVE, wMove ) ;
1161 EnableMenuItem( hMenu, SC_SIZE, wSize ) ;
1162 EnableMenuItem( hMenu, SC_MINIMIZE, wMinBox ) ;
1163 EnableMenuItem( hMenu, SC_MAXIMIZE, wMaxBox ) ;
1164 EnableMenuItem( hMenu, SC_RESTORE, wRestore ) ;
1165
1166 } // SetupSystemMenu()
1167
1168 // GetCaptionRect( HWND hWnd, LPRECT lprc )
1169 //
1170 // calcluales the rectangle of the mini-caption in screen coords.
1171 //
1172 BOOL PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc )
1173 {
1174 UINT nCapSize ;
1175
1176 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1177
1178 if (!HASCAPTION( hWnd ))
1179 {
1180 SetRectEmpty( lprc ) ;
1181 return FALSE ;
1182 }
1183
1184 GetWindowRect( hWnd, lprc ) ;
1185
1186 // the window might have other non-client components like
1187 // borders
1188 //
1189 if (TestWinStyle( hWnd, WS_THICKFRAME ))
1190 {
1191 lprc->left += GetSystemMetrics( SM_CXFRAME ) ;
1192 lprc->top += GetSystemMetrics( SM_CYFRAME ) ;
1193 lprc->right -= GetSystemMetrics( SM_CXFRAME ) ;
1194 lprc->bottom -= GetSystemMetrics( SM_CYFRAME ) ;
1195 }
1196 else
1197 if (TestWinStyle( hWnd, DS_MODALFRAME )) // if it's a dialog box
1198 {
1199 lprc->left += GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ;
1200 lprc->top += GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ;
1201 lprc->right -= GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ;
1202 lprc->bottom -= GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ;
1203 }
1204 else
1205 if (TestWinStyle( hWnd, WS_BORDER ))
1206 {
1207 lprc->left += GetSystemMetrics( SM_CXBORDER ) ;
1208 lprc->top += GetSystemMetrics( SM_CYBORDER ) ;
1209 lprc->right -= GetSystemMetrics( SM_CXBORDER ) ;
1210 lprc->bottom -= GetSystemMetrics( SM_CYBORDER ) ;
1211 }
1212
1213 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1214 lprc->right = lprc->left + nCapSize ;
1215 else
1216 lprc->bottom = lprc->top + nCapSize ;
1217
1218 return TRUE ;
1219 } // GetCaptionRect()
1220
1221 // GetIconRect( HWND hWnd, LPRECT lprc )
1222 //
1223 // Calculates the rect of the icon in screen coordinates.
1224 //
1225 BOOL PASCAL GetIconRect( HWND hWnd, LPRECT lprc )
1226 {
1227 UINT nCapSize ;
1228 BOOL fMenu, fVert ;
1229
1230 fMenu= TestWinStyle( hWnd, WS_SYSMENU ) ;
1231 fVert = TestWinStyle( hWnd, IBS_VERTCAPTION ) ;
1232
1233 if (!GetCaptionRect( hWnd, lprc )) // window coords
1234 return FALSE ;
1235
1236 if (!fMenu)
1237 {
1238 SetRectEmpty( lprc ) ;
1239 return FALSE ;
1240 }
1241
1242 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1243
1244 if (fVert)
1245 lprc->bottom = lprc->top + nCapSize ;
1246 else
1247 lprc->right = lprc->left + nCapSize ;
1248
1249 lprc->bottom-- ;
1250 lprc->right-- ;
1251
1252 return TRUE ;
1253
1254 } // GetIconRect()
1255
1256 // GetMinButtonRect()
1257 //
1258 // Calculates the rect of the minimize button in screen
1259 // coordinates.
1260 //
1261 // For horizontal captions, we have the following situation ('Y' is minimize
1262 // and '^' is maximize or restore):
1263 //
1264 // +---------------------------------+
1265 // | - | | Y | ^ |
1266 // +---------------------------------+
1267 // | |.......| <-- This is the width (nSize)
1268 //
1269 // For vertical captions, we have the following:
1270 //
1271 // | |
1272 // | |
1273 // | |
1274 // | |
1275 // | |
1276 // | |
1277 // |--|--
1278 // | Y| .
1279 // |--| . <-- This is the height of the rectangle (nSize)
1280 // | ^| .
1281 // +--+--
1282 //
1283 // In order to figure out where the minimize button goes, we first need
1284 // to know if there is a maximize button. If so, use GetMaxButtonRect()
1285 // to place...
1286 //
1287 BOOL PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc )
1288 {
1289 if (!TestWinStyle( hWnd, WS_MINIMIZEBOX ))
1290 {
1291 SetRectEmpty( lprc ) ;
1292 return FALSE ;
1293 }
1294
1295 // The minimize button can be in either position 1 or 2. If there
1296 // is a maximize button, it's in position 2.
1297 //
1298 if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ))
1299 return GetButtonRect( hWnd, 2, lprc ) ;
1300 else
1301 return GetButtonRect( hWnd, 1, lprc ) ;
1302 }
1303
1304 // GetMaxButtonRect()
1305 //
1306 // Calculates the rect of the maximize button in screen
1307 // coordinates.
1308 //
1309 // The maximize button, if present, is always to the far right
1310 // or bottom.
1311 //
1312 BOOL PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc )
1313 {
1314 //The maximize button can only be in position 1.
1315 //
1316 if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ))
1317 return GetButtonRect( hWnd, 1, lprc ) ;
1318 else
1319 {
1320 SetRectEmpty( lprc ) ;
1321 return FALSE ;
1322 }
1323 }
1324
1325 // Get the rect where a button would go.
1326 //
1327 // This function does not care if it's a min or max, just whether
1328 // it is the first from the right/bottom or second from the right/bottom
1329 // and so on..
1330 //
1331 BOOL PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc )
1332 {
1333 UINT nSize = 0 ;
1334
1335 if (!GetCaptionRect( hWnd, lprc )) //window coords
1336 return FALSE ;
1337
1338 nSize = GETCAPTIONSIZE( hWnd ) ;
1339
1340 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1341 {
1342 lprc->bottom -= nSize * (nPos-1) ;
1343 lprc->top = lprc->bottom - nSize + 1 ;
1344 }
1345 else
1346 {
1347 lprc->right -= nSize * (nPos-1) ;
1348 lprc->left = lprc->right - nSize + 1 ;
1349 }
1350
1351 return TRUE ;
1352 } // GetButtonRect()
1353
1354 // DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed )
1355 //
1356 // Draws either the min, max, or restore buttons. If fMin is FALSE then it
1357 // will draw either the Max or Restore button. If fDepressed is TRUE it will
1358 // draw the button in a down state.
1359 //
1360 void PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed)
1361 {
1362 RECT rcButton ;
1363 RECT rc ;
1364 COLORREF rgbWindowFrame ;
1365 BOOL fDC ;
1366 UINT nCapSize ;
1367 UINT nOffset ;
1368 int n ;
1369
1370 nCapSize = GETCAPTIONSIZE( hWnd ) ;
1371
1372 // If you look at the standard Windows' min/max buttons, you will notice
1373 // that they have two pixels of 'shadow' to the bottom and right. Since
1374 // our buttons can be really, really small, we only want one pixel of
1375 // shadow when they are small. I arbitrarily decided that if the
1376 // caption size is greater than or equal to 20 we will use two
1377 // pixels. That's what this THREASHOLD stuff does.
1378 //
1379 #define THRESHOLD 20
1380 nOffset = (nCapSize >= THRESHOLD) ? 2 : 1 ;
1381
1382 if (!hDC)
1383 {
1384 fDC = TRUE ;
1385 hDC = GetWindowDC( hWnd ) ;
1386 }
1387 else
1388 fDC = FALSE ;
1389
1390 if (hDC)
1391 {
1392 rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
1393
1394 if (fMin)
1395 GetMinButtonRect( hWnd, &rcButton ) ;
1396 else
1397 GetMaxButtonRect( hWnd, &rcButton ) ;
1398
1399 GetWindowRect( hWnd, &rc ) ;
1400 OffsetRect( &rcButton, -rc.left, -rc.top ) ;
1401
1402 rc = rcButton ;
1403 if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
1404 {
1405 rc = rcButton ; //separator line
1406 rc.bottom = --rc.top + 1 ;
1407 rcButton.right-- ;
1408 }
1409 else
1410 {
1411 rc = rcButton ; //separator line
1412 rc.right = --rc.left + 1 ;
1413 rcButton.bottom-- ;
1414 }
1415
1416 //Draw separator line
1417 SetBkColor( hDC, rgbWindowFrame ) ;
1418 DRAWFASTRECT( hDC, &rc ) ;
1419
1420 //Fill
1421 SetBkColor( hDC, RGBLTGRAY ) ;
1422 DRAWFASTRECT( hDC, &rcButton ) ;
1423
1424 if (!fDepressed)
1425 {
1426 //The normal min/max buttons have one pixel on the top and left
1427 //sides for the highlight, and two pixels on the bottom and
1428 //right side for the shadow.
1429 //
1430 //When our caption is 'small' we only use one pixel on all
1431 //sides.
1432 //
1433 SetBkColor( hDC, RGBWHITE ) ;
1434 //Draw left side
1435 rc = rcButton ;
1436 rc.right = rc.left + 1 ;
1437 DRAWFASTRECT( hDC, &rc ) ;
1438
1439 //Draw Top
1440 rc = rcButton ;
1441 rc.bottom = rc.top + 1 ;
1442 DRAWFASTRECT( hDC, &rc ) ;
1443
1444 SetBkColor( hDC, RGBGRAY ) ;
1445 //Draw right side
1446 rc = rcButton ;
1447 rc.left = rc.right - 1 ;
1448 DRAWFASTRECT( hDC, &rc ) ;
1449 if (nCapSize > THRESHOLD)
1450 {
1451 rc.left-- ;
1452 rc.top++ ;
1453 DRAWFASTRECT( hDC, &rc ) ;
1454 }
1455
1456 //Draw bottom
1457 rc = rcButton ;
1458 rc.top = rc.bottom - 1 ;
1459 DRAWFASTRECT( hDC, &rc ) ;
1460 if (nCapSize > THRESHOLD)
1461 {
1462 rc.top-- ;
1463 rc.left++ ;
1464 DRAWFASTRECT( hDC, &rc ) ;
1465 }
1466
1467 rcButton.left++ ;
1468 rcButton.top++ ;
1469 rcButton.right -= nOffset ;
1470 rcButton.bottom -= nOffset ;
1471 }
1472 else
1473 {
1474 //Draw depressed state
1475
1476 SetBkColor( hDC, RGBGRAY ) ;
1477 //Draw left side
1478 rc = rcButton ;
1479 rc.right = rc.left + nOffset ;
1480 DRAWFASTRECT( hDC, &rc ) ;
1481
1482 //Draw Top
1483 rc = rcButton ;
1484 rc.bottom = rc.top + nOffset ;
1485 DRAWFASTRECT( hDC, &rc ) ;
1486
1487 rcButton.left += 2 * nOffset ;
1488 rcButton.top += 2 * nOffset ;
1489 }
1490
1491 // Now draw the arrows. We do not want the
1492 // arrows to grow too large when we have a bigger than
1493 // normal caption, so we restrict their size.
1494 //
1495 // rcButton now represents where we can place our
1496 // arrows.
1497 //
1498 // The maximum size of our arrows (i.e. the width of rcButton)
1499 // has been empirically determined to be SM_CYCAPTION / 2
1500 //
1501 n = ((GetSystemMetrics( SM_CYCAPTION )) / 2) -
1502 (rcButton.right - rcButton.left) ;
1503 if (n < 1)
1504 InflateRect( &rcButton, n/2-1, n/2-1 ) ;
1505
1506 if (fMin)
1507 DrawArrow( hDC, &rcButton, ARROW_DOWN ) ;
1508 else
1509 if (IsZoomed( hWnd ))
1510 {
1511 DrawArrow( hDC, &rcButton, ARROW_RESTORE ) ;
1512 }
1513 else
1514 DrawArrow( hDC, &rcButton, ARROW_UP ) ;
1515
1516 if (fDC)
1517 ReleaseDC( hWnd, hDC ) ;
1518 }
1519
1520 } // DrawButton()
1521
1522
1523 // DrawArrow
1524 //
1525 // Draws either a up or down arrow. The arrow is bound by the rectangle
1526 //
1527 void PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle )
1528 {
1529 int row ;
1530 int xTip ;
1531 int yTip ;
1532 RECT rc ;
1533 int nMax = (lprc->bottom - lprc->top) >> 1 ;
1534
1535 SetBkColor( hdc, RGBBLACK ) ;
1536
1537 // We draw the arrow by drawing a series of horizontal lines
1538 //
1539 xTip = lprc->left + ((lprc->right - lprc->left+1) >> 1) ;
1540 switch (uiStyle)
1541 {
1542 case ARROW_UP:
1543 yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 2) ;
1544 for (row = 1 ; row <= nMax ; row++ )
1545 {
1546 rc.left = xTip - row ;
1547 rc.right = xTip + row - 1 ;
1548 rc.top = yTip + row ;
1549 rc.bottom = rc.top + 1 ;
1550 DRAWFASTRECT( hdc, &rc ) ;
1551 }
1552 break ;
1553
1554 case ARROW_DOWN:
1555 yTip = lprc->bottom - ((lprc->bottom - lprc->top-1) >> 2) ;
1556 for ( row = nMax ; row > 0 ; 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_RESTORE:
1567 default:
1568 yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 3) - 2;
1569 for (row = 1 ; row <= nMax ; row++ )
1570 {
1571 rc.left = xTip - row ;
1572 rc.right = xTip + row - 1 ;
1573 rc.top = yTip + row ;
1574 rc.bottom = rc.top + 1 ;
1575 DRAWFASTRECT( hdc, &rc ) ;
1576 }
1577
1578 yTip += (nMax+1) * 2 ;
1579 for ( row = nMax ; row > 0 ; 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 break ;
1588 }
1589
1590 } // DrawArrow()
1591
1592 #endif // USE_ITSY_BITSY