OSDN Git Service

Show Ignore Sub Menu
[tortoisegit/TortoiseGitJp.git] / src / Utils / MiscUI / OddButton.cpp
1 /*\r
2  * Copyright (c) 2001-2002 Paolo Messina and Jerzy Kaczorowski\r
3  * \r
4  * The contents of this file are subject to the Artistic License (the "License").\r
5  * You may not use this file except in compliance with the License. \r
6  * You may obtain a copy of the License at:\r
7  * http://www.opensource.org/licenses/artistic-license.html\r
8  * \r
9  * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED \r
10  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF \r
11  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
12  * \r
13  */\r
14 \r
15 // OddButton.cpp : implementation file\r
16 //\r
17 \r
18 #include "stdafx.h"\r
19 #include "OddButton.h"\r
20 \r
21 #ifdef _DEBUG\r
22 #define new DEBUG_NEW\r
23 #undef THIS_FILE\r
24 static char THIS_FILE[] = __FILE__;\r
25 #endif\r
26 \r
27 /////////////////////////////////////////////////////////////////////////////\r
28 // COddButton\r
29 \r
30 COddButton::COddButton()\r
31 {\r
32         m_bDefault = FALSE;\r
33         m_bCanBeDefault = FALSE;\r
34         \r
35         // invalid value, since type still unknown\r
36         m_nTypeStyle = ODDBTN_BS_TYPEMASK;\r
37 }\r
38 \r
39 COddButton::~COddButton()\r
40 {\r
41 }\r
42 \r
43 \r
44 BEGIN_MESSAGE_MAP(COddButton, CButton)\r
45         //{{AFX_MSG_MAP(COddButton)\r
46         ON_WM_GETDLGCODE()\r
47         //}}AFX_MSG_MAP\r
48         ON_MESSAGE(BM_SETSTYLE, OnSetStyle)\r
49 END_MESSAGE_MAP()\r
50 \r
51 /////////////////////////////////////////////////////////////////////////////\r
52 // COddButton message handlers\r
53 \r
54 /*!\r
55         PreSubclassWindow virtual override\r
56 \r
57         Initialize internal data members and verify that the BS_OWNERDRAW style is set\r
58         \note COddButton::PreSubclassWindow should be called if overrided in a derived class\r
59 */\r
60 void COddButton::PreSubclassWindow() \r
61 {\r
62         // set initial control type\r
63         m_nTypeStyle = GetStyle() & ODDBTN_BS_TYPEMASK;\r
64 \r
65         // set initial default state flag\r
66         if (m_nTypeStyle == BS_DEFPUSHBUTTON)\r
67         {\r
68                 // enable default state handling for push buttons\r
69                 m_bCanBeDefault = TRUE;\r
70 \r
71                 // set default state for a default button\r
72                 m_bDefault = TRUE;\r
73 \r
74                 // adjust style for default button\r
75                 m_nTypeStyle = BS_PUSHBUTTON;\r
76         }\r
77         else if (m_nTypeStyle == BS_PUSHBUTTON)\r
78         {\r
79                 // enable default state handling for push buttons\r
80                 m_bCanBeDefault = TRUE;\r
81         }\r
82 \r
83         // you should not set the Owner Draw before this call\r
84         // (don't use the resource editor "Owner Draw" or\r
85         // ModifyStyle(0, BS_OWNERDRAW) before calling PreSubclassWindow() )\r
86         ASSERT(m_nTypeStyle != BS_OWNERDRAW);\r
87 \r
88         // switch to owner-draw\r
89         ModifyStyle(ODDBTN_BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);\r
90 \r
91         CButton::PreSubclassWindow();\r
92 }\r
93 \r
94 /// WM_GETDLGCODE message handler, indicate to the system whether we want to handle default state\r
95 UINT COddButton::OnGetDlgCode() \r
96 {\r
97         UINT nCode = CButton::OnGetDlgCode();\r
98 \r
99         // handle standard control types\r
100         switch (GetControlType())\r
101         {\r
102         case BS_RADIOBUTTON:\r
103         case BS_AUTORADIOBUTTON:\r
104                 nCode |= DLGC_RADIOBUTTON;\r
105                 break;\r
106 \r
107         case BS_GROUPBOX:\r
108                 nCode = DLGC_STATIC;\r
109                 break;\r
110         }\r
111 \r
112         // tell the system if we want default state handling\r
113         // (losing default state always allowed)\r
114         if (m_bCanBeDefault || m_bDefault)\r
115                 nCode |= (m_bDefault ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);\r
116 \r
117         return nCode;\r
118 }\r
119 \r
120 /// BM_SETSTYLE message handler, update internal default state data member\r
121 LRESULT COddButton::OnSetStyle(WPARAM wParam, LPARAM lParam)\r
122 {\r
123         UINT_PTR nNewType = (wParam & ODDBTN_BS_TYPEMASK);\r
124 \r
125         // update default state flag\r
126         if (nNewType == BS_DEFPUSHBUTTON)\r
127         {\r
128                 // we must like default state at this point\r
129                 ASSERT(m_bCanBeDefault);\r
130 \r
131                 m_bDefault = TRUE;\r
132         }\r
133         else if (nNewType == BS_PUSHBUTTON)\r
134         {\r
135                 // losing default state always allowed\r
136                 m_bDefault = FALSE;\r
137         }\r
138 \r
139         // can't change control type after owner-draw is set.\r
140         // let the system process changes to other style bits\r
141         // and redrawing, while keeping owner-draw style\r
142         return DefWindowProc(BM_SETSTYLE,\r
143                 (wParam & ~ODDBTN_BS_TYPEMASK) | BS_OWNERDRAW, lParam);\r
144 }\r
145 \r
146 /////////////////////////////////////////////////////////////////////////////\r
147 // COddButton methods\r
148 \r
149 /*!\r
150         Get the type of control to draw\r
151         \return The of control\r
152 */\r
153 UINT COddButton::GetControlType() const\r
154 {\r
155         return m_nTypeStyle;\r
156 }\r
157 \r
158 /*!\r
159         Get the control's default state\r
160         \return TRUE if control has a default state, FALSE otherwise\r
161 */\r
162 BOOL COddButton::IsDefault() const\r
163 {\r
164         // if we have default state, we must like it!\r
165         ASSERT((m_bCanBeDefault && m_bDefault) == m_bDefault);\r
166 \r
167         return m_bDefault;\r
168 }\r
169 \r
170 /*!\r
171         Enable default state handling \r
172         \param bEnable TRUE to enable default state handling, FALSE to disable\r
173 */\r
174 void COddButton::EnableDefault(BOOL bEnable)\r
175 {\r
176         m_bCanBeDefault = bEnable;\r
177 \r
178         // disabling default when control has default state\r
179         // needs removing the default state\r
180         if (!bEnable && m_bDefault)\r
181         {\r
182                 // remove default state\r
183                 SendMessage(BM_SETSTYLE, (GetStyle() & ~ODDBTN_BS_TYPEMASK) | BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));\r
184                 ASSERT(m_bDefault == FALSE);\r
185 \r
186                 // update default button\r
187                 CWnd* pParent = GetParent();\r
188                 if( pParent )\r
189                 {\r
190                         LRESULT lRes = pParent->SendMessage(DM_GETDEFID);\r
191                         if (HIWORD(lRes) == DC_HASDEFID)\r
192                         {\r
193                                 pParent->SendMessage(DM_SETDEFID, LOWORD(lRes));\r
194                         }\r
195                 }\r
196         }\r
197 }\r
198 \r
199 /*!\r
200         Set the dialog's default pushbutton\r
201         \param pDialog Dialog to set the default pushbutton\r
202         \param nID Button ID to make default\r
203         \note It fixes the drawing problem that sometimes occurs when using plain CDialog::SetDefID,\r
204         see also MS kb Q67655 (<A HREF="http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q67655&">\r
205         HOWTO: Change or Set the Default Push Button in a Dialog Box</A>)\r
206 */\r
207 void COddButton::SetDefID(CDialog* pDialog, const UINT nID)\r
208 {\r
209         if( !pDialog || !::IsWindow(pDialog->m_hWnd) )\r
210         {\r
211                 ASSERT(FALSE); // Bad pointer or dialog is not a window\r
212                 return;\r
213         }\r
214 \r
215         // get the current default button\r
216         const DWORD dwPrevDefID = pDialog->GetDefID();\r
217         const UINT nPrevID = (HIWORD(dwPrevDefID) == DC_HASDEFID) ? LOWORD(dwPrevDefID) : 0;\r
218                 \r
219         /*\r
220          *      Set the new default ID in the dialog\r
221          */\r
222         pDialog->SetDefID(nID);\r
223 \r
224         /*\r
225          *      Make sure the previous default button doesn't have the default state anymore\r
226          */\r
227 \r
228         // check previous ID is a default-compatible button\r
229         // and it has the default state\r
230         LRESULT lRes = (nPrevID == 0) ? 0 : pDialog->SendDlgItemMessage(nPrevID, WM_GETDLGCODE);\r
231         if( (lRes & DLGC_BUTTON) && \r
232                 (lRes & DLGC_DEFPUSHBUTTON) )\r
233         {\r
234                 pDialog->SendDlgItemMessage(nPrevID, BM_SETSTYLE,\r
235                         BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));\r
236         }\r
237         \r
238         /*\r
239          *      Make sure the new default button receives the default state\r
240          */\r
241 \r
242         // check new ID is a button\r
243         lRes = (nID == 0) ? 0 : pDialog->SendDlgItemMessage(nID, WM_GETDLGCODE);\r
244         if( lRes & DLGC_BUTTON )\r
245         {\r
246                 // exception: current focused button should keep its default state (IMHO)\r
247                 CWnd* pFocusWnd = GetFocus();\r
248                 LRESULT lResFocus = (pFocusWnd == NULL) ? 0 : pFocusWnd->SendMessage(WM_GETDLGCODE);\r
249 \r
250                 // check focused control is a default-compatible button\r
251                 if( (lResFocus & DLGC_BUTTON) && \r
252                         (lResFocus & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)) )\r
253                 {\r
254                         // remove default state (if needed)\r
255                         if( (lRes & DLGC_DEFPUSHBUTTON) && \r
256                                 (nID != (UINT)pFocusWnd->GetDlgCtrlID()) )\r
257                         {\r
258                                 pDialog->SendDlgItemMessage(nID, BM_SETSTYLE,\r
259                                         BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));\r
260                         }\r
261 \r
262                         // set default state (if needed)\r
263                         if( lResFocus & DLGC_UNDEFPUSHBUTTON )\r
264                         {\r
265                                 pFocusWnd->SendMessage(BM_SETSTYLE,\r
266                                         BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));\r
267                         }\r
268                 }\r
269                 else if( lRes & DLGC_UNDEFPUSHBUTTON )\r
270                 {\r
271                         // not default-compatible button has the focus\r
272                         // set default state\r
273                         pDialog->SendDlgItemMessage(nID, BM_SETSTYLE,\r
274                                 BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));\r
275                 }\r
276         }\r
277 }\r