]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/ctrlcmn.cpp
Add support for MSW unique volume names to wxFileName.
[wxWidgets.git] / src / common / ctrlcmn.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/ctrlcmn.cpp
3// Purpose: wxControl common interface
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 26.07.99
7// RCS-ID: $Id$
8// Copyright: (c) wxWidgets team
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_CONTROLS
28
29#include "wx/control.h"
30
31#ifndef WX_PRECOMP
32 #include "wx/dc.h"
33 #include "wx/log.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"
39#endif
40
41const char wxControlNameStr[] = "control";
42
43// ============================================================================
44// implementation
45// ============================================================================
46
47wxControlBase::~wxControlBase()
48{
49 // this destructor is required for Darwin
50}
51
52bool wxControlBase::Create(wxWindow *parent,
53 wxWindowID id,
54 const wxPoint &pos,
55 const wxSize &size,
56 long style,
57 const wxValidator& wxVALIDATOR_PARAM(validator),
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
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
81 wxCHECK_MSG( parent, false, wxT("all controls must have parents") );
82
83 if ( !CreateBase(parent, id, pos, size, style, validator, name) )
84 return false;
85
86 parent->AddChild(this);
87
88 return true;
89}
90
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
98void wxControlBase::Command(wxCommandEvent& event)
99{
100 (void)GetEventHandler()->ProcessEvent(event);
101}
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 {
111 case wxClientData_Void:
112 event.SetClientData(GetClientData());
113 break;
114
115 case wxClientData_Object:
116 event.SetClientObject(GetClientObject());
117 break;
118
119 case wxClientData_None:
120 // nothing to do
121 ;
122 }
123}
124
125bool wxControlBase::SetFont(const wxFont& font)
126{
127 InvalidateBestSize();
128 return wxWindow::SetFont(font);
129}
130
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
157/* static */
158wxString wxControlBase::RemoveMnemonics(const wxString& str)
159{
160 return wxStripMenuCodes(str, wxStrip_Mnemonics);
161}
162
163/* static */
164wxString wxControlBase::EscapeMnemonics(const wxString& text)
165{
166 wxString label(text);
167 label.Replace("&", "&&");
168 return label;
169}
170
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
177 static const wxChar MNEMONIC_PREFIX = wxT('&');
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 {
202 wxFAIL_MSG(wxT("duplicate accel char in control label"));
203 }
204 }
205 }
206
207 if ( labelOnly )
208 {
209 *labelOnly += *pc;
210 }
211 }
212
213 return indexAccel;
214}
215
216wxBorder wxControlBase::GetDefaultBorder() const
217{
218 return wxBORDER_THEME;
219}
220
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
232// ----------------------------------------------------------------------------
233// wxControlBase - ellipsization code
234// ----------------------------------------------------------------------------
235
236#define wxELLIPSE_REPLACEMENT wxT("...")
237
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
248 wxASSERT_MSG( mode != wxELLIPSIZE_NONE, "shouldn't be called at all then" );
249
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!)
271 wxASSERT(excessPixels>0);
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 {
279 case wxELLIPSIZE_START:
280 initialChar = 0;
281 for ( nChars=0;
282 nChars < len && charOffsets[nChars] < excessPixels;
283 nChars++ )
284 ;
285 break;
286
287 case wxELLIPSIZE_MIDDLE:
288 {
289 // the start & end of the removed span of chars
290 initialChar = len/2;
291 size_t endChar = len/2;
292
293 int removed = 0;
294 for ( ; removed < excessPixels; )
295 {
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 }
324 }
325
326 initialChar++;
327 nChars = endChar - initialChar + 1;
328 }
329 break;
330
331 case wxELLIPSIZE_END:
332 {
333 wxASSERT(len > 0);
334
335 int maxWidth = totalWidth - excessPixels;
336 for ( initialChar = 0;
337 initialChar < len && charOffsets[initialChar] < maxWidth;
338 initialChar++ )
339 ;
340
341 if (initialChar == 0)
342 {
343 nChars = len;
344 }
345 else
346 {
347 //initialChar--; // go back one character
348 nChars = len - initialChar;
349 }
350 }
351 break;
352
353 case wxELLIPSIZE_NONE:
354 default:
355 wxFAIL_MSG("invalid ellipsize mode");
356 return curLine;
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)
372 ret.insert(initialChar, wxELLIPSE_REPLACEMENT);
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
382/* static */
383wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc,
384 wxEllipsizeMode mode, int maxFinalWidth,
385 int flags)
386{
387 wxString ret;
388
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();
394
395 // NB: we must handle correctly labels with newlines:
396 wxString curLine;
397 for ( wxString::const_iterator pc = label.begin(); ; ++pc )
398 {
399 if ( pc == label.end() || *pc == wxS('\n') )
400 {
401 curLine = DoEllipsizeSingleLine(curLine, dc, mode, maxFinalWidth,
402 replacementWidth, marginWidth);
403
404 // add this (ellipsized) row to the rest of the label
405 ret << curLine;
406 if ( pc == label.end() )
407 {
408 // NOTE: this is the return which always exits the function
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
418 else if ( *pc == wxS('&') && (flags & wxELLIPSIZE_FLAGS_PROCESS_MNEMONICS) )
419 {
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
425 }
426 // we need also to expand tabs to properly calc their size
427 else if ( *pc == wxS('\t') && (flags & wxELLIPSIZE_FLAGS_EXPAND_TABS) )
428 {
429 // Windows natively expands the TABs to 6 spaces. Do the same:
430 curLine += wxS(" ");
431 }
432 else
433 {
434 curLine += *pc;
435 }
436 }
437
438 // this return would generate a
439 // warning C4702: unreachable code
440 // with MSVC since the function always exits from inside the loop
441 //return ret;
442}
443
444
445
446// ----------------------------------------------------------------------------
447// wxStaticBitmap
448// ----------------------------------------------------------------------------
449
450#if wxUSE_STATBMP
451
452wxStaticBitmapBase::~wxStaticBitmapBase()
453{
454 // this destructor is required for Darwin
455}
456
457wxSize wxStaticBitmapBase::DoGetBestSize() const
458{
459 wxSize best;
460 wxBitmap bmp = GetBitmap();
461 if ( bmp.Ok() )
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;
468}
469
470#endif // wxUSE_STATBMP
471
472#endif // wxUSE_CONTROLS