1///////////////////////////////////////////////////////////////////////////// 2// Name: src/motif/button.cpp 3// Purpose: wxButton 4// Author: Julian Smart 5// Modified by: 6// Created: 17/09/98 7// RCS-ID: $Id: button.cpp 50982 2008-01-01 20:38:33Z VZ $ 8// Copyright: (c) Julian Smart 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#ifdef __VMS__ 18#pragma message disable nosimpint 19#endif 20#include <Xm/PushBG.h> 21#include <Xm/PushB.h> 22#ifdef __VMS__ 23#pragma message enable nosimpint 24#endif 25 26 27#ifndef WX_PRECOMP 28 #include "wx/toplevel.h" 29#endif 30 31#include "wx/stockitem.h" 32#include "wx/motif/private.h" 33#include "wx/sysopt.h" 34 35void wxButtonCallback (Widget w, XtPointer clientData, XtPointer ptr); 36 37IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl) 38 39#define MIN_WIDTH 78 40#define MIN_LARGE_HEIGHT 30 41 42// Button 43 44bool wxButton::Create(wxWindow *parent, wxWindowID id, const wxString& lbl, 45 const wxPoint& pos, 46 const wxSize& size, long style, 47 const wxValidator& validator, 48 const wxString& name) 49{ 50 wxString label(lbl); 51 if (label.empty() && wxIsStockID(id)) 52 label = wxGetStockLabel(id); 53 54 if( !CreateControl( parent, id, pos, size, style, validator, name ) ) 55 return false; 56 57 wxXmString text( GetLabelText(label) ); 58 59 Widget parentWidget = (Widget) parent->GetClientWidget(); 60 61 /* 62 * Patch Note (important) 63 * There is no major reason to put a defaultButtonThickness here. 64 * Not requesting it give the ability to put wxButton with a spacing 65 * as small as requested. However, if some button become a DefaultButton, 66 * other buttons are no more aligned -- This is why we set 67 * defaultButtonThickness of ALL buttons belonging to the same wxPanel, 68 * in the ::SetDefaultButton method. 69 */ 70 m_mainWidget = (WXWidget) XtVaCreateManagedWidget ("button", 71 xmPushButtonWidgetClass, 72 parentWidget, 73 wxFont::GetFontTag(), m_font.GetFontTypeC(XtDisplay(parentWidget)), 74 XmNlabelString, text(), 75 XmNrecomputeSize, False, 76 // See comment for wxButton::SetDefault 77 // XmNdefaultButtonShadowThickness, 1, 78 NULL); 79 80 XtAddCallback ((Widget) m_mainWidget, 81 XmNactivateCallback, (XtCallbackProc) wxButtonCallback, 82 (XtPointer) this); 83 84 wxSize best = GetBestSize(); 85 if( size.x != -1 ) best.x = size.x; 86 if( size.y != -1 ) best.y = size.y; 87 88 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, 89 pos.x, pos.y, best.x, best.y); 90 91 ChangeBackgroundColour(); 92 93 return true; 94} 95 96void wxButton::SetDefaultShadowThicknessAndResize() 97{ 98 Widget buttonWidget = (Widget)GetMainWidget(); 99 bool managed = XtIsManaged( buttonWidget ); 100 if( managed ) 101 XtUnmanageChild( buttonWidget ); 102 103 XtVaSetValues( buttonWidget, 104 XmNdefaultButtonShadowThickness, 1, 105 NULL ); 106 107 if( managed ) 108 XtManageChild( buttonWidget ); 109 110 // this can't currently be done, because user code that calls SetDefault 111 // will break otherwise 112#if 0 113 wxSize best = GetBestSize(), actual = GetSize(); 114 if( best.x < actual.x ) best.x = actual.x; 115 if( best.y < actual.y ) best.y = actual.y; 116 117 if( best != actual ) 118 SetSize( best ); 119#endif 120 InvalidateBestSize(); 121} 122 123 124void wxButton::SetDefault() 125{ 126 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); 127 if ( tlw ) 128 tlw->SetDefaultItem(this); 129 130 // We initially do not set XmNdefaultShadowThickness, to have 131 // small buttons. Unfortunately, buttons are now mis-aligned. We 132 // try to correct this now -- setting this ressource to 1 for each 133 // button in the same row. Because it's very hard to find 134 // wxButton in the same row, correction is straighforward: we set 135 // resource for all wxButton in this parent (but not sub panels) 136 137 wxWindow *parent = GetParent(); 138 for (wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst (); 139 node; node = node->GetNext ()) 140 { 141 wxWindow *win = node->GetData (); 142 wxButton *item = wxDynamicCast(win, wxButton); 143 if (item) 144 item->SetDefaultShadowThicknessAndResize(); 145 } 146 147 XtVaSetValues ((Widget) parent->GetMainWidget(), 148 XmNdefaultButton, (Widget) GetMainWidget(), 149 NULL); 150} 151 152static inline bool wxMotifLargeButtons() 153{ 154 return wxSystemOptions::HasOption("motif.largebuttons") 155 && wxSystemOptions::GetOptionInt("motif.largebuttons") != 0; 156} 157 158/* static */ 159wxSize wxButton::GetDefaultSize() 160{ 161 // TODO: check font size as in wxMSW ? MB 162 // Note: this is the button size (text + margin + shadow + defaultBorder) 163 return wxSize( MIN_WIDTH, MIN_LARGE_HEIGHT ); 164} 165 166wxSize wxButton::DoGetBestSize() const 167{ 168 if( wxMotifLargeButtons() ) 169 return OldGetBestSize(); 170 171 wxSize best = wxControl::DoGetBestSize(); 172 173 if( HasFlag( wxBU_EXACTFIT ) ) 174 return best; 175 else if( best.x < MIN_WIDTH ) 176 best.x = MIN_WIDTH; 177 178 return best; 179} 180 181wxSize wxButton::GetMinSize() const 182{ 183 if( wxMotifLargeButtons() ) 184 return OldGetMinSize(); 185 186 return DoGetBestSize(); 187} 188 189wxSize wxButton::OldGetMinSize() const 190{ 191 return OldGetBestSize(); 192} 193 194wxSize wxButton::OldGetBestSize() const 195{ 196 Dimension xmargin, ymargin, highlight, shadow, defThickness; 197 198 XtVaGetValues( (Widget)m_mainWidget, 199 XmNmarginWidth, &xmargin, 200 XmNmarginHeight, &ymargin, 201 XmNhighlightThickness, &highlight, 202 XmNshadowThickness, &shadow, 203 XmNdefaultButtonShadowThickness, &defThickness, 204 NULL ); 205 206 int x = 0; int y = 0; 207 GetTextExtent( GetLabel(), &x, &y ); 208 209 int margin = highlight * 2 + 210 ( defThickness ? ( ( shadow + defThickness ) * 4 ) : ( shadow * 2 ) ); 211 212 wxSize best( x + xmargin * 2 + margin, 213 y + ymargin * 2 + margin ); 214 215 // all buttons have at least the standard size unless the user explicitly 216 // wants them to be of smaller size and used wxBU_EXACTFIT style when 217 // creating the button 218 if( !HasFlag( wxBU_EXACTFIT ) ) 219 { 220 wxSize def = GetDefaultSize(); 221 int margin = highlight * 2 + 222 ( defThickness ? ( shadow * 4 + defThickness * 4 ) : 0 ); 223 def.x += margin; 224 def.y += margin; 225 226 if( def.x > best.x ) 227 best.x = def.x; 228 if( def.y > best.y ) 229 best.y = def.y; 230 } 231 232 return best; 233} 234 235void wxButton::Command (wxCommandEvent & event) 236{ 237 ProcessCommand (event); 238} 239 240void wxButtonCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr)) 241{ 242 if (!wxGetWindowFromTable(w)) 243 // Widget has been deleted! 244 return; 245 246 wxButton *item = (wxButton *) clientData; 247 wxCommandEvent event (wxEVT_COMMAND_BUTTON_CLICKED, item->GetId()); 248 event.SetEventObject(item); 249 item->ProcessCommand (event); 250} 251