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