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