]> git.saurik.com Git - wxWidgets.git/blob - src/os2/button.cpp
Warning fix.
[wxWidgets.git] / src / os2 / button.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/os2/button.cpp
3 // Purpose:     wxButton
4 // Author:      David Webster
5 // Modified by:
6 // Created:     10/13/99
7 // RCS-ID:      $Id$
8 // Copyright:   (c) David Webster
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #include "wx/button.h"
16
17 #ifndef WX_PRECOMP
18     #include "wx/app.h"
19     #include "wx/brush.h"
20     #include "wx/panel.h"
21     #include "wx/bmpbuttn.h"
22     #include "wx/settings.h"
23     #include "wx/dcscreen.h"
24     #include "wx/scrolwin.h"
25     #include "wx/toplevel.h"
26 #endif
27
28 #include "wx/stockitem.h"
29 #include "wx/os2/private.h"
30
31 #define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10)
32
33 //
34 // Should be at the very least less than winDEFAULT_BUTTON_MARGIN
35 //
36 #define FOCUS_MARGIN 3
37
38 #ifndef BST_CHECKED
39 #define BST_CHECKED 0x0001
40 #endif
41
42 IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl)
43
44 // Button
45
46 bool wxButton::Create( wxWindow*          pParent,
47                        wxWindowID         vId,
48                        const wxString&    rsLbl,
49                        const wxPoint&     rPos,
50                        const wxSize&      rSize,
51                        long               lStyle,
52                        const wxValidator& rValidator,
53                        const wxString&    rsName)
54 {
55     wxString rsLabel(rsLbl);
56     if (rsLabel.empty() && wxIsStockID(vId))
57         rsLabel = wxGetStockLabel(vId);
58
59     wxString                        sLabel = ::wxPMTextToLabel(rsLabel);
60
61     SetName(rsName);
62 #if wxUSE_VALIDATORS
63     SetValidator(rValidator);
64 #endif
65     m_windowStyle = lStyle;
66     pParent->AddChild((wxButton *)this);
67     if (vId == -1)
68         m_windowId = NewControlId();
69     else
70         m_windowId = vId;
71     lStyle = WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON;
72
73     //
74     // OS/2 PM does not have Right/Left/Top/Bottom styles.
75     // We will have to define an additional style when we implement notebooks
76     // for a notebook page button
77     //
78     if (m_windowStyle & wxCLIP_SIBLINGS )
79         lStyle |= WS_CLIPSIBLINGS;
80
81     m_hWnd = (WXHWND)::WinCreateWindow( GetHwndOf(pParent)   // Parent handle
82                                        ,WC_BUTTON            // A Button class window
83                                        ,(PSZ)sLabel.c_str()  // Button text
84                                        ,lStyle               // Button style
85                                        ,0, 0, 0, 0           // Location and size
86                                        ,GetHwndOf(pParent)   // Owner handle
87                                        ,HWND_TOP             // Top of Z-Order
88                                        ,vId                  // Identifier
89                                        ,NULL                 // No control data
90                                        ,NULL                 // No Presentation parameters
91                                       );
92     if (m_hWnd == 0)
93     {
94         return false;
95     }
96
97     //
98     // Subclass again for purposes of dialog editing mode
99     //
100     SubclassWin(m_hWnd);
101     wxFont*                          pButtonFont = new wxFont( 8
102                                                               ,wxSWISS
103                                                               ,wxNORMAL
104                                                               ,wxNORMAL
105                                                              );
106     SetFont(*pButtonFont);
107     SetXComp(0);
108     SetYComp(0);
109     SetSize( rPos.x
110             ,rPos.y
111             ,rSize.x
112             ,rSize.y
113            );
114     delete pButtonFont;
115     return true;
116 } // end of wxButton::Create
117
118 wxButton::~wxButton()
119 {
120     wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
121
122     if (tlw)
123     {
124         if (tlw->GetDefaultItem() == this)
125         {
126             //
127             // Don't leave the panel with invalid default item
128             //
129             tlw->SetDefaultItem(NULL);
130         }
131     }
132 } // end of wxButton::~wxButton
133
134 // ----------------------------------------------------------------------------
135 // size management including autosizing
136 // ----------------------------------------------------------------------------
137
138 wxSize wxButton::DoGetBestSize() const
139 {
140     wxString                        rsLabel = wxGetWindowText(GetHWND());
141     int                             nWidthButton;
142     int                             nWidthChar;
143     int                             nHeightChar;
144     wxFont                          vFont = (wxFont)GetFont();
145
146     GetTextExtent( rsLabel
147                   ,&nWidthButton
148                   ,NULL
149                  );
150
151     wxGetCharSize( GetHWND()
152                   ,&nWidthChar
153                   ,&nHeightChar
154                   ,&vFont
155                  );
156
157     //
158     // Add a margin - the button is wider than just its label
159     //
160     nWidthButton += 3 * nWidthChar;
161
162     //
163     // The button height is proportional to the height of the font used
164     //
165     int                             nHeightButton = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(nHeightChar);
166
167     //
168     // Need a little extra to make it look right
169     //
170     nHeightButton += (int)(nHeightChar/1.5);
171
172     if (!HasFlag(wxBU_EXACTFIT))
173     {
174         wxSize                      vSize = GetDefaultSize();
175
176         if (nWidthButton > vSize.x)
177             vSize.x = nWidthButton;
178         if (nHeightButton > vSize.y)
179             vSize.y = nHeightButton;
180         return vSize;
181     }
182     return wxSize( nWidthButton
183                   ,nHeightButton
184                  );
185 } // end of wxButton::DoGetBestSize
186
187 /* static */
188 wxSize wxButton::GetDefaultSize()
189 {
190     static wxSize                   vSizeBtn;
191
192     if (vSizeBtn.x == 0)
193     {
194         wxScreenDC                  vDc;
195
196         vDc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
197
198         //
199         // The size of a standard button in the dialog units is 50x14,
200         // translate this to pixels
201         // NB1: the multipliers come from the Windows convention
202         // NB2: the extra +1/+2 were needed to get the size be the same as the
203         //      size of the buttons in the standard dialog - I don't know how
204         //      this happens, but on my system this size is 75x23 in pixels and
205         //      23*8 isn't even divisible by 14... Would be nice to understand
206         //      why these constants are needed though!
207         vSizeBtn.x = (50 * (vDc.GetCharWidth() + 1))/4;
208         vSizeBtn.y = ((14 * vDc.GetCharHeight()) + 2)/8;
209     }
210     return vSizeBtn;
211 } // end of wxButton::GetDefaultSize
212
213 void wxButton::Command (
214   wxCommandEvent&                   rEvent
215 )
216 {
217     ProcessCommand (rEvent);
218 } // end of wxButton::Command
219
220 // ----------------------------------------------------------------------------
221 // helpers
222 // ----------------------------------------------------------------------------
223
224 bool wxButton::SendClickEvent()
225 {
226     wxCommandEvent                  vEvent( wxEVT_COMMAND_BUTTON_CLICKED
227                                            ,GetId()
228                                           );
229
230     vEvent.SetEventObject(this);
231     return ProcessCommand(vEvent);
232 } // end of wxButton::SendClickEvent
233
234 void wxButton::SetDefault()
235 {
236     wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
237
238     wxCHECK_RET( tlw, _T("button without top level window?") );
239
240     //
241     // Set this one as the default button both for wxWidgets and Windows
242     //
243     wxWindow*                       pWinOldDefault = tlw->SetDefaultItem(this);
244
245     SetDefaultStyle( wxDynamicCast(pWinOldDefault, wxButton), false);
246     SetDefaultStyle( this, true );
247 } // end of wxButton::SetDefault
248
249 void wxButton::SetTmpDefault()
250 {
251     wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
252
253     wxCHECK_RET( tlw, _T("button without top level window?") );
254
255     wxWindow*                       pWinOldDefault = tlw->GetDefaultItem();
256
257     tlw->SetTmpDefaultItem(this);
258     SetDefaultStyle( wxDynamicCast(pWinOldDefault, wxButton), false);
259     SetDefaultStyle( this, true );
260 } // end of wxButton::SetTmpDefault
261
262 void wxButton::UnsetTmpDefault()
263 {
264     wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
265
266     wxCHECK_RET( tlw, _T("button without top level window?") );
267
268     tlw->SetTmpDefaultItem(NULL);
269
270     wxWindow*                       pWinOldDefault = tlw->GetDefaultItem();
271
272     SetDefaultStyle( this, false );
273     SetDefaultStyle( wxDynamicCast(pWinOldDefault, wxButton), true );
274 } // end of wxButton::UnsetTmpDefault
275
276 void wxButton::SetDefaultStyle(
277   wxButton*                         pBtn
278 , bool                              bOn
279 )
280 {
281     long                            lStyle;
282     //
283     // We may be called with NULL pointer -- simpler to do the check here than
284     // in the caller which does wxDynamicCast()
285     //
286     if (!pBtn)
287         return;
288
289     //
290     // First, let DefDlgProc() know about the new default button
291     //
292     if (bOn)
293     {
294         if (!wxTheApp->IsActive())
295             return;
296
297         //
298         // In OS/2 the dialog/panel doesn't really know it has a default
299         // button, the default button simply has that style.  We'll just
300         // simulate by setting focus to it
301         //
302         pBtn->SetFocus();
303     }
304     lStyle = ::WinQueryWindowULong(GetHwndOf(pBtn), QWL_STYLE);
305     if (!(lStyle & BS_DEFAULT) == bOn)
306     {
307         if ((lStyle & BS_USERBUTTON) != BS_USERBUTTON)
308         {
309             if (bOn)
310                 lStyle |= BS_DEFAULT;
311             else
312                 lStyle &= ~BS_DEFAULT;
313             ::WinSetWindowULong(GetHwndOf(pBtn), QWL_STYLE, lStyle);
314         }
315         else
316         {
317             //
318             // Redraw the button - it will notice itself that it's not the
319             // default one any longer
320             //
321             pBtn->Refresh();
322         }
323     }
324 } // end of wxButton::UpdateDefaultStyle
325
326 // ----------------------------------------------------------------------------
327 // event/message handlers
328 // ----------------------------------------------------------------------------
329
330 bool wxButton::OS2Command(WXUINT uParam, WXWORD WXUNUSED(wId))
331 {
332     bool bProcessed = false;
333
334     switch (uParam)
335     {
336         case BN_CLICKED:            // normal buttons send this
337         case BN_DBLCLICKED:         // owner-drawn ones also send this
338             bProcessed = SendClickEvent();
339             break;
340     }
341
342     return bProcessed;
343 } // end of wxButton::OS2Command
344
345 WXHBRUSH wxButton::OnCtlColor( WXHDC    WXUNUSED(pDC),
346                                WXHWND   WXUNUSED(pWnd),
347                                WXUINT   WXUNUSED(nCtlColor),
348                                WXUINT   WXUNUSED(uMessage),
349                                WXWPARAM WXUNUSED(wParam),
350                                WXLPARAM WXUNUSED(lParam) )
351 {
352     wxBrush* pBackgroundBrush = wxTheBrushList->FindOrCreateBrush( GetBackgroundColour()
353                                                                   ,wxSOLID
354                                                                   );
355
356     return (WXHBRUSH)pBackgroundBrush->GetResourceHandle();
357 } // end of wxButton::OnCtlColor
358
359 void wxButton::MakeOwnerDrawn()
360 {
361     long                            lStyle = 0L;
362
363     lStyle = ::WinQueryWindowULong(GetHwnd(), QWL_STYLE);
364     if ((lStyle & BS_USERBUTTON) != BS_USERBUTTON)
365     {
366         //
367         // Make it so
368         //
369         lStyle |= BS_USERBUTTON;
370         ::WinSetWindowULong(GetHwnd(), QWL_STYLE, lStyle);
371     }
372 } // end of wxButton::MakeOwnerDrawn
373
374 WXDWORD wxButton::OS2GetStyle(
375   long                              lStyle
376 , WXDWORD*                          pdwExstyle
377 ) const
378 {
379     //
380     // Buttons never have an external border, they draw their own one
381     //
382     WXDWORD                         dwStyle = wxControl::OS2GetStyle( (lStyle & ~wxBORDER_MASK) | wxBORDER_NONE
383                                                                      ,pdwExstyle
384                                                                     );
385
386     //
387     // We must use WS_CLIPSIBLINGS with the buttons or they would draw over
388     // each other in any resizeable dialog which has more than one button in
389     // the bottom
390     //
391     dwStyle |= WS_CLIPSIBLINGS;
392     return dwStyle;
393 } // end of wxButton::OS2GetStyle
394
395 MRESULT wxButton::WindowProc( WXUINT   uMsg,
396                               WXWPARAM wParam,
397                               WXLPARAM lParam )
398 {
399     //
400     // When we receive focus, we want to temporary become the default button in
401     // our parent panel so that pressing "Enter" would activate us -- and when
402     // losing it we should restore the previous default button as well
403     //
404     if (uMsg == WM_SETFOCUS)
405     {
406         if (SHORT1FROMMP(lParam) == TRUE)
407             SetTmpDefault();
408         else
409             UnsetTmpDefault();
410
411         //
412         // Let the default processign take place too
413         //
414     }
415
416     else if (uMsg == WM_BUTTON1DBLCLK)
417     {
418         //
419         // Emulate a click event to force an owner-drawn button to change its
420         // appearance - without this, it won't do it
421         //
422         (void)wxControl::OS2WindowProc( WM_BUTTON1DOWN
423                                        ,wParam
424                                        ,lParam
425                                       );
426
427         //
428         // And conitnue with processing the message normally as well
429         //
430     }
431
432     //
433     // Let the base class do all real processing
434     //
435     return (wxControl::OS2WindowProc( uMsg
436                                      ,wParam
437                                      ,lParam
438                                     ));
439 } // end of wxWindowProc