1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/ctrlcmn.cpp
3 // Purpose: wxControl common interface
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/control.h"
34 #include "wx/radiobut.h"
35 #include "wx/statbmp.h"
36 #include "wx/bitmap.h"
37 #include "wx/utils.h" // for wxStripMenuCodes()
38 #include "wx/settings.h"
41 const char wxControlNameStr
[] = "control";
43 // ============================================================================
45 // ============================================================================
47 wxControlBase::~wxControlBase()
49 // this destructor is required for Darwin
52 bool wxControlBase::Create(wxWindow
*parent
,
57 const wxValidator
& wxVALIDATOR_PARAM(validator
),
60 bool ret
= wxWindow::Create(parent
, id
, pos
, size
, style
, name
);
64 SetValidator(validator
);
65 #endif // wxUSE_VALIDATORS
70 bool wxControlBase::CreateControl(wxWindowBase
*parent
,
75 const wxValidator
& validator
,
78 // even if it's possible to create controls without parents in some port,
79 // it should surely be discouraged because it doesn't work at all under
81 wxCHECK_MSG( parent
, false, wxT("all controls must have parents") );
83 if ( !CreateBase(parent
, id
, pos
, size
, style
, validator
, name
) )
86 parent
->AddChild(this);
92 wxString
wxControlBase::GetLabelText(const wxString
& label
)
94 // we don't want strip the TABs here, just the mnemonics
95 return wxStripMenuCodes(label
, wxStrip_Mnemonics
);
98 void wxControlBase::Command(wxCommandEvent
& event
)
100 (void)GetEventHandler()->ProcessEvent(event
);
103 void wxControlBase::InitCommandEvent(wxCommandEvent
& event
) const
105 event
.SetEventObject((wxControlBase
*)this); // const_cast
107 // event.SetId(GetId()); -- this is usuall done in the event ctor
109 switch ( m_clientDataType
)
111 case wxClientData_Void
:
112 event
.SetClientData(GetClientData());
115 case wxClientData_Object
:
116 event
.SetClientObject(GetClientObject());
119 case wxClientData_None
:
125 bool wxControlBase::SetFont(const wxFont
& font
)
127 InvalidateBestSize();
128 return wxWindow::SetFont(font
);
131 // wxControl-specific processing after processing the update event
132 void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent
& event
)
135 wxWindowBase::DoUpdateWindowUI(event
);
138 if ( event
.GetSetText() )
140 if ( event
.GetText() != GetLabel() )
141 SetLabel(event
.GetText());
144 // Unfortunately we don't yet have common base class for
145 // wxRadioButton, so we handle updates of radiobuttons here.
146 // TODO: If once wxRadioButtonBase will exist, move this code there.
148 if ( event
.GetSetChecked() )
150 wxRadioButton
*radiobtn
= wxDynamicCastThis(wxRadioButton
);
152 radiobtn
->SetValue(event
.GetChecked());
154 #endif // wxUSE_RADIOBTN
158 wxString
wxControlBase::RemoveMnemonics(const wxString
& str
)
160 return wxStripMenuCodes(str
, wxStrip_Mnemonics
);
164 wxString
wxControlBase::EscapeMnemonics(const wxString
& text
)
166 wxString
label(text
);
167 label
.Replace("&", "&&");
172 int wxControlBase::FindAccelIndex(const wxString
& label
, wxString
*labelOnly
)
174 // the character following MNEMONIC_PREFIX is the accelerator for this
175 // control unless it is MNEMONIC_PREFIX too - this allows to insert
176 // literal MNEMONIC_PREFIX chars into the label
177 static const wxChar MNEMONIC_PREFIX
= wxT('&');
182 labelOnly
->Alloc(label
.length());
186 for ( wxString::const_iterator pc
= label
.begin(); pc
!= label
.end(); ++pc
)
188 if ( *pc
== MNEMONIC_PREFIX
)
191 if ( pc
== label
.end() )
193 else if ( *pc
!= MNEMONIC_PREFIX
)
195 if ( indexAccel
== -1 )
197 // remember it (-1 is for MNEMONIC_PREFIX itself
198 indexAccel
= pc
- label
.begin() - 1;
202 wxFAIL_MSG(wxT("duplicate accel char in control label"));
216 wxBorder
wxControlBase::GetDefaultBorder() const
218 return wxBORDER_THEME
;
221 /* static */ wxVisualAttributes
222 wxControlBase::GetCompositeControlsDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
224 wxVisualAttributes attrs
;
225 attrs
.font
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
226 attrs
.colFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
);
227 attrs
.colBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
);
232 // ----------------------------------------------------------------------------
233 // wxControlBase - ellipsization code
234 // ----------------------------------------------------------------------------
236 #define wxELLIPSE_REPLACEMENT wxT("...")
238 /* static and protected */
239 wxString
wxControlBase::DoEllipsizeSingleLine(const wxString
& curLine
, const wxDC
& dc
,
240 wxEllipsizeMode mode
, int maxFinalWidth
,
241 int replacementWidth
, int marginWidth
)
243 wxASSERT_MSG(replacementWidth
> 0 && marginWidth
> 0,
244 "Invalid parameters");
245 wxASSERT_MSG(!curLine
.Contains('\n'),
246 "Use Ellipsize() instead!");
248 wxASSERT_MSG( mode
!= wxELLIPSIZE_NONE
, "shouldn't be called at all then" );
250 // NOTE: this function assumes that any mnemonic/tab character has already
251 // been handled if it was necessary to handle them (see Ellipsize())
253 if (maxFinalWidth
<= 0)
254 return wxEmptyString
;
256 wxArrayInt charOffsets
;
257 size_t len
= curLine
.length();
259 !dc
.GetPartialTextExtents(curLine
, charOffsets
))
262 wxASSERT(charOffsets
.GetCount() == len
);
264 size_t totalWidth
= charOffsets
.Last();
265 if ( totalWidth
<= (size_t)maxFinalWidth
)
266 return curLine
; // we don't need to do any ellipsization!
268 int excessPixels
= totalWidth
- maxFinalWidth
+
270 marginWidth
; // security margin (NEEDED!)
271 wxASSERT(excessPixels
>0);
273 // remove characters in excess
274 size_t initialChar
, // index of first char to erase
275 nChars
; // how many chars do we need to erase?
279 case wxELLIPSIZE_START
:
282 nChars
< len
&& charOffsets
[nChars
] < excessPixels
;
287 case wxELLIPSIZE_MIDDLE
:
289 // the start & end of the removed span of chars
291 size_t endChar
= len
/2;
294 for ( ; removed
< excessPixels
; )
298 // width of the initialChar-th character
299 int width
= charOffsets
[initialChar
] -
300 charOffsets
[initialChar
-1];
302 // remove the initialChar-th character
307 if (endChar
< len
- 1 &&
308 removed
< excessPixels
)
310 // width of the (endChar+1)-th character
311 int width
= charOffsets
[endChar
+1] -
312 charOffsets
[endChar
];
314 // remove the endChar-th character
319 if (initialChar
== 0 && endChar
== len
-1)
327 nChars
= endChar
- initialChar
+ 1;
331 case wxELLIPSIZE_END
:
335 int maxWidth
= totalWidth
- excessPixels
;
336 for ( initialChar
= 0;
337 initialChar
< len
&& charOffsets
[initialChar
] < maxWidth
;
341 if (initialChar
== 0)
347 //initialChar--; // go back one character
348 nChars
= len
- initialChar
;
353 case wxELLIPSIZE_NONE
:
355 wxFAIL_MSG("invalid ellipsize mode");
359 wxString
ret(curLine
);
362 // need to remove the entire row!
367 // erase nChars characters after initialChar (included):
368 ret
.erase(initialChar
, nChars
+1);
370 // if there is space for the replacement dots, add them
371 if (maxFinalWidth
> replacementWidth
)
372 ret
.insert(initialChar
, wxELLIPSE_REPLACEMENT
);
375 // if everything was ok, we should have shortened this line
376 // enough to make it fit in maxFinalWidth:
377 wxASSERT(dc
.GetTextExtent(ret
).GetWidth() < maxFinalWidth
);
383 wxString
wxControlBase::Ellipsize(const wxString
& label
, const wxDC
& dc
,
384 wxEllipsizeMode mode
, int maxFinalWidth
,
389 // these cannot be cached between different Ellipsize() calls as they can
390 // change because of e.g. a font change; however we calculate them only once
391 // when ellipsizing multiline labels:
392 int replacementWidth
= dc
.GetTextExtent(wxELLIPSE_REPLACEMENT
).GetWidth();
393 int marginWidth
= dc
.GetCharWidth();
395 // NB: we must handle correctly labels with newlines:
397 for ( wxString::const_iterator pc
= label
.begin(); ; ++pc
)
399 if ( pc
== label
.end() || *pc
== wxS('\n') )
401 curLine
= DoEllipsizeSingleLine(curLine
, dc
, mode
, maxFinalWidth
,
402 replacementWidth
, marginWidth
);
404 // add this (ellipsized) row to the rest of the label
406 if ( pc
== label
.end() )
408 // NOTE: this is the return which always exits the function
417 // we need to remove mnemonics from the label for correct calculations
418 else if ( *pc
== wxS('&') && (flags
& wxELLIPSIZE_FLAGS_PROCESS_MNEMONICS
) )
420 // pc+1 is safe: at worst we'll be at end()
421 wxString::const_iterator next
= pc
+ 1;
422 if ( next
!= label
.end() && *next
== wxS('&') )
423 curLine
+= wxS('&'); // && becomes &
424 //else: remove this ampersand
426 // we need also to expand tabs to properly calc their size
427 else if ( *pc
== wxS('\t') && (flags
& wxELLIPSIZE_FLAGS_EXPAND_TABS
) )
429 // Windows natively expands the TABs to 6 spaces. Do the same:
438 // this return would generate a
439 // warning C4702: unreachable code
440 // with MSVC since the function always exits from inside the loop
446 // ----------------------------------------------------------------------------
448 // ----------------------------------------------------------------------------
452 wxStaticBitmapBase::~wxStaticBitmapBase()
454 // this destructor is required for Darwin
457 wxSize
wxStaticBitmapBase::DoGetBestSize() const
460 wxBitmap bmp
= GetBitmap();
462 best
= wxSize(bmp
.GetWidth(), bmp
.GetHeight());
464 // this is completely arbitrary
465 best
= wxSize(16, 16);
470 #endif // wxUSE_STATBMP
472 #endif // wxUSE_CONTROLS