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