]> git.saurik.com Git - wxWidgets.git/blame - src/common/ctrlcmn.cpp
Add support for MSW unique volume names to wxFileName.
[wxWidgets.git] / src / common / ctrlcmn.cpp
CommitLineData
2d61b48d 1/////////////////////////////////////////////////////////////////////////////
0e2d2986 2// Name: src/common/ctrlcmn.cpp
2d61b48d
VZ
3// Purpose: wxControl common interface
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 26.07.99
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets team
65571936 9// Licence: wxWindows licence
2d61b48d
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2d61b48d
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
1e6feb95
VZ
27#if wxUSE_CONTROLS
28
93fbbe07
WS
29#include "wx/control.h"
30
2d61b48d 31#ifndef WX_PRECOMP
02b4f9fd 32 #include "wx/dc.h"
2d61b48d 33 #include "wx/log.h"
0e2d2986 34 #include "wx/radiobut.h"
e267406e 35 #include "wx/statbmp.h"
1e6feb95 36 #include "wx/bitmap.h"
74639764 37 #include "wx/utils.h" // for wxStripMenuCodes()
0534259a 38 #include "wx/settings.h"
0bca0373 39#endif
1e6feb95 40
f36e602b 41const char wxControlNameStr[] = "control";
e7445ff8 42
2d61b48d
VZ
43// ============================================================================
44// implementation
45// ============================================================================
46
799ea011
GD
47wxControlBase::~wxControlBase()
48{
49 // this destructor is required for Darwin
50}
51
1e6feb95
VZ
52bool wxControlBase::Create(wxWindow *parent,
53 wxWindowID id,
54 const wxPoint &pos,
55 const wxSize &size,
56 long style,
ac8d0c11 57 const wxValidator& wxVALIDATOR_PARAM(validator),
1e6feb95
VZ
58 const wxString &name)
59{
60 bool ret = wxWindow::Create(parent, id, pos, size, style, name);
61
62#if wxUSE_VALIDATORS
63 if ( ret )
64 SetValidator(validator);
65#endif // wxUSE_VALIDATORS
66
67 return ret;
68}
69
2d61b48d
VZ
70bool wxControlBase::CreateControl(wxWindowBase *parent,
71 wxWindowID id,
72 const wxPoint& pos,
73 const wxSize& size,
74 long style,
75 const wxValidator& validator,
76 const wxString& name)
77{
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
80 // Windows
c9d59ee7 81 wxCHECK_MSG( parent, false, wxT("all controls must have parents") );
2d61b48d
VZ
82
83 if ( !CreateBase(parent, id, pos, size, style, validator, name) )
c9d59ee7 84 return false;
2d61b48d
VZ
85
86 parent->AddChild(this);
87
c9d59ee7 88 return true;
2d61b48d
VZ
89}
90
74639764
VZ
91/* static */
92wxString wxControlBase::GetLabelText(const wxString& label)
93{
94 // we don't want strip the TABs here, just the mnemonics
95 return wxStripMenuCodes(label, wxStrip_Mnemonics);
96}
97
2d61b48d
VZ
98void wxControlBase::Command(wxCommandEvent& event)
99{
bfbd6dc1 100 (void)GetEventHandler()->ProcessEvent(event);
2d61b48d 101}
bfbd6dc1
VZ
102
103void wxControlBase::InitCommandEvent(wxCommandEvent& event) const
104{
105 event.SetEventObject((wxControlBase *)this); // const_cast
106
107 // event.SetId(GetId()); -- this is usuall done in the event ctor
108
109 switch ( m_clientDataType )
110 {
1e6feb95 111 case wxClientData_Void:
bfbd6dc1
VZ
112 event.SetClientData(GetClientData());
113 break;
114
1e6feb95 115 case wxClientData_Object:
bfbd6dc1
VZ
116 event.SetClientObject(GetClientObject());
117 break;
118
1e6feb95 119 case wxClientData_None:
bfbd6dc1
VZ
120 // nothing to do
121 ;
122 }
123}
124
9f884528
RD
125bool wxControlBase::SetFont(const wxFont& font)
126{
127 InvalidateBestSize();
128 return wxWindow::SetFont(font);
129}
130
a3a4105d
VZ
131// wxControl-specific processing after processing the update event
132void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
133{
134 // call inherited
135 wxWindowBase::DoUpdateWindowUI(event);
136
137 // update label
138 if ( event.GetSetText() )
139 {
140 if ( event.GetText() != GetLabel() )
141 SetLabel(event.GetText());
142 }
143
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.
147#if wxUSE_RADIOBTN
148 if ( event.GetSetChecked() )
149 {
150 wxRadioButton *radiobtn = wxDynamicCastThis(wxRadioButton);
151 if ( radiobtn )
152 radiobtn->SetValue(event.GetChecked());
153 }
154#endif // wxUSE_RADIOBTN
155}
156
39bc0347
VZ
157/* static */
158wxString wxControlBase::RemoveMnemonics(const wxString& str)
159{
160 return wxStripMenuCodes(str, wxStrip_Mnemonics);
161}
162
5b8b2c84
VZ
163/* static */
164wxString wxControlBase::EscapeMnemonics(const wxString& text)
165{
166 wxString label(text);
167 label.Replace("&", "&&");
168 return label;
169}
170
916eabe6
VZ
171/* static */
172int wxControlBase::FindAccelIndex(const wxString& label, wxString *labelOnly)
173{
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
9a83f860 177 static const wxChar MNEMONIC_PREFIX = wxT('&');
916eabe6
VZ
178
179 if ( labelOnly )
180 {
181 labelOnly->Empty();
182 labelOnly->Alloc(label.length());
183 }
184
185 int indexAccel = -1;
186 for ( wxString::const_iterator pc = label.begin(); pc != label.end(); ++pc )
187 {
188 if ( *pc == MNEMONIC_PREFIX )
189 {
190 ++pc; // skip it
191 if ( pc == label.end() )
192 break;
193 else if ( *pc != MNEMONIC_PREFIX )
194 {
195 if ( indexAccel == -1 )
196 {
197 // remember it (-1 is for MNEMONIC_PREFIX itself
198 indexAccel = pc - label.begin() - 1;
199 }
200 else
201 {
9a83f860 202 wxFAIL_MSG(wxT("duplicate accel char in control label"));
916eabe6
VZ
203 }
204 }
205 }
206
207 if ( labelOnly )
208 {
209 *labelOnly += *pc;
210 }
211 }
212
213 return indexAccel;
214}
215
a78618b0
FM
216wxBorder wxControlBase::GetDefaultBorder() const
217{
218 return wxBORDER_THEME;
219}
220
0534259a
VZ
221/* static */ wxVisualAttributes
222wxControlBase::GetCompositeControlsDefaultAttributes(wxWindowVariant WXUNUSED(variant))
223{
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);
228
229 return attrs;
230}
231
a78618b0
FM
232// ----------------------------------------------------------------------------
233// wxControlBase - ellipsization code
234// ----------------------------------------------------------------------------
235
5c87527c
FM
236#define wxELLIPSE_REPLACEMENT wxT("...")
237
a78618b0
FM
238/* static and protected */
239wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxDC& dc,
240 wxEllipsizeMode mode, int maxFinalWidth,
241 int replacementWidth, int marginWidth)
242{
243 wxASSERT_MSG(replacementWidth > 0 && marginWidth > 0,
244 "Invalid parameters");
245 wxASSERT_MSG(!curLine.Contains('\n'),
246 "Use Ellipsize() instead!");
247
c937bcac
VZ
248 wxASSERT_MSG( mode != wxELLIPSIZE_NONE, "shouldn't be called at all then" );
249
a78618b0
FM
250 // NOTE: this function assumes that any mnemonic/tab character has already
251 // been handled if it was necessary to handle them (see Ellipsize())
252
253 if (maxFinalWidth <= 0)
254 return wxEmptyString;
255
256 wxArrayInt charOffsets;
257 size_t len = curLine.length();
258 if (len == 0 ||
259 !dc.GetPartialTextExtents(curLine, charOffsets))
260 return curLine;
261
262 wxASSERT(charOffsets.GetCount() == len);
263
264 size_t totalWidth = charOffsets.Last();
265 if ( totalWidth <= (size_t)maxFinalWidth )
266 return curLine; // we don't need to do any ellipsization!
267
268 int excessPixels = totalWidth - maxFinalWidth +
269 replacementWidth +
270 marginWidth; // security margin (NEEDED!)
91d55088 271 wxASSERT(excessPixels>0);
a78618b0
FM
272
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?
276
277 switch (mode)
278 {
8d6e8e45
VZ
279 case wxELLIPSIZE_START:
280 initialChar = 0;
281 for ( nChars=0;
282 nChars < len && charOffsets[nChars] < excessPixels;
283 nChars++ )
284 ;
285 break;
a78618b0 286
8d6e8e45 287 case wxELLIPSIZE_MIDDLE:
a78618b0 288 {
8d6e8e45
VZ
289 // the start & end of the removed span of chars
290 initialChar = len/2;
291 size_t endChar = len/2;
a78618b0 292
8d6e8e45
VZ
293 int removed = 0;
294 for ( ; removed < excessPixels; )
a78618b0 295 {
8d6e8e45
VZ
296 if (initialChar > 0)
297 {
298 // width of the initialChar-th character
299 int width = charOffsets[initialChar] -
300 charOffsets[initialChar-1];
301
302 // remove the initialChar-th character
303 removed += width;
304 initialChar--;
305 }
306
307 if (endChar < len - 1 &&
308 removed < excessPixels)
309 {
310 // width of the (endChar+1)-th character
311 int width = charOffsets[endChar+1] -
312 charOffsets[endChar];
313
314 // remove the endChar-th character
315 removed += width;
316 endChar++;
317 }
318
319 if (initialChar == 0 && endChar == len-1)
320 {
321 nChars = len+1;
322 break;
323 }
a78618b0
FM
324 }
325
8d6e8e45
VZ
326 initialChar++;
327 nChars = endChar - initialChar + 1;
a78618b0 328 }
8d6e8e45 329 break;
a78618b0 330
8d6e8e45
VZ
331 case wxELLIPSIZE_END:
332 {
333 wxASSERT(len > 0);
a78618b0 334
8d6e8e45
VZ
335 int maxWidth = totalWidth - excessPixels;
336 for ( initialChar = 0;
337 initialChar < len && charOffsets[initialChar] < maxWidth;
338 initialChar++ )
339 ;
a78618b0 340
8d6e8e45
VZ
341 if (initialChar == 0)
342 {
343 nChars = len;
344 }
345 else
346 {
347 //initialChar--; // go back one character
348 nChars = len - initialChar;
349 }
a78618b0 350 }
8d6e8e45 351 break;
a78618b0 352
c937bcac 353 case wxELLIPSIZE_NONE:
8d6e8e45
VZ
354 default:
355 wxFAIL_MSG("invalid ellipsize mode");
356 return curLine;
a78618b0
FM
357 }
358
359 wxString ret(curLine);
360 if (nChars >= len)
361 {
362 // need to remove the entire row!
363 ret.clear();
364 }
365 else
366 {
367 // erase nChars characters after initialChar (included):
368 ret.erase(initialChar, nChars+1);
369
370 // if there is space for the replacement dots, add them
371 if (maxFinalWidth > replacementWidth)
91d55088 372 ret.insert(initialChar, wxELLIPSE_REPLACEMENT);
a78618b0
FM
373 }
374
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);
378
379 return ret;
380}
381
5c87527c
FM
382/* static */
383wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc,
a78618b0
FM
384 wxEllipsizeMode mode, int maxFinalWidth,
385 int flags)
5c87527c 386{
5c87527c
FM
387 wxString ret;
388
a78618b0
FM
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:
5c87527c 392 int replacementWidth = dc.GetTextExtent(wxELLIPSE_REPLACEMENT).GetWidth();
a78618b0 393 int marginWidth = dc.GetCharWidth();
5c87527c
FM
394
395 // NB: we must handle correctly labels with newlines:
396 wxString curLine;
5c87527c
FM
397 for ( wxString::const_iterator pc = label.begin(); ; ++pc )
398 {
a78618b0 399 if ( pc == label.end() || *pc == wxS('\n') )
5c87527c 400 {
a78618b0
FM
401 curLine = DoEllipsizeSingleLine(curLine, dc, mode, maxFinalWidth,
402 replacementWidth, marginWidth);
5c87527c
FM
403
404 // add this (ellipsized) row to the rest of the label
405 ret << curLine;
406 if ( pc == label.end() )
407 {
7d27b626 408 // NOTE: this is the return which always exits the function
5c87527c
FM
409 return ret;
410 }
411 else
412 {
413 ret << *pc;
414 curLine.clear();
415 }
416 }
417 // we need to remove mnemonics from the label for correct calculations
355ce7ad 418 else if ( *pc == wxS('&') && (flags & wxELLIPSIZE_FLAGS_PROCESS_MNEMONICS) )
5c87527c
FM
419 {
420 // pc+1 is safe: at worst we'll be at end()
421 wxString::const_iterator next = pc + 1;
a78618b0
FM
422 if ( next != label.end() && *next == wxS('&') )
423 curLine += wxS('&'); // && becomes &
5c87527c
FM
424 //else: remove this ampersand
425 }
426 // we need also to expand tabs to properly calc their size
355ce7ad 427 else if ( *pc == wxS('\t') && (flags & wxELLIPSIZE_FLAGS_EXPAND_TABS) )
5c87527c
FM
428 {
429 // Windows natively expands the TABs to 6 spaces. Do the same:
a78618b0 430 curLine += wxS(" ");
5c87527c
FM
431 }
432 else
433 {
434 curLine += *pc;
435 }
436 }
437
02b4f9fd 438 // this return would generate a
7d27b626 439 // warning C4702: unreachable code
02b4f9fd 440 // with MSVC since the function always exits from inside the loop
7d27b626 441 //return ret;
5c87527c
FM
442}
443
dc797d8e
JS
444
445
1e6feb95
VZ
446// ----------------------------------------------------------------------------
447// wxStaticBitmap
448// ----------------------------------------------------------------------------
449
450#if wxUSE_STATBMP
451
799ea011
GD
452wxStaticBitmapBase::~wxStaticBitmapBase()
453{
454 // this destructor is required for Darwin
455}
456
b3fcfa4d 457wxSize wxStaticBitmapBase::DoGetBestSize() const
1e6feb95 458{
9f884528 459 wxSize best;
1e6feb95
VZ
460 wxBitmap bmp = GetBitmap();
461 if ( bmp.Ok() )
9f884528
RD
462 best = wxSize(bmp.GetWidth(), bmp.GetHeight());
463 else
464 // this is completely arbitrary
465 best = wxSize(16, 16);
466 CacheBestSize(best);
467 return best;
1e6feb95
VZ
468}
469
470#endif // wxUSE_STATBMP
471
472#endif // wxUSE_CONTROLS