+/* static */
+wxString wxControlBase::EscapeMnemonics(const wxString& text)
+{
+ wxString label(text);
+ label.Replace("&", "&&");
+ return label;
+}
+
+/* static */
+int wxControlBase::FindAccelIndex(const wxString& label, wxString *labelOnly)
+{
+ // the character following MNEMONIC_PREFIX is the accelerator for this
+ // control unless it is MNEMONIC_PREFIX too - this allows to insert
+ // literal MNEMONIC_PREFIX chars into the label
+ static const wxChar MNEMONIC_PREFIX = _T('&');
+
+ if ( labelOnly )
+ {
+ labelOnly->Empty();
+ labelOnly->Alloc(label.length());
+ }
+
+ int indexAccel = -1;
+ for ( wxString::const_iterator pc = label.begin(); pc != label.end(); ++pc )
+ {
+ if ( *pc == MNEMONIC_PREFIX )
+ {
+ ++pc; // skip it
+ if ( pc == label.end() )
+ break;
+ else if ( *pc != MNEMONIC_PREFIX )
+ {
+ if ( indexAccel == -1 )
+ {
+ // remember it (-1 is for MNEMONIC_PREFIX itself
+ indexAccel = pc - label.begin() - 1;
+ }
+ else
+ {
+ wxFAIL_MSG(_T("duplicate accel char in control label"));
+ }
+ }
+ }
+
+ if ( labelOnly )
+ {
+ *labelOnly += *pc;
+ }
+ }
+
+ return indexAccel;
+}
+
+#define wxELLIPSE_REPLACEMENT wxT("...")
+
+/* static */
+wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc,
+ wxEllipsizeMode mode, int maxFinalWidth)
+{
+ wxArrayInt charOffsets;
+ wxString ret;
+
+ // these cannot be cached as they can change because of e.g. a font change
+ int replacementWidth = dc.GetTextExtent(wxELLIPSE_REPLACEMENT).GetWidth();
+ int marginWidth = dc.GetCharWidth()*2;
+
+ // NB: we must handle correctly labels with newlines:
+ wxString curLine;
+ wxSize reqsize;
+ size_t len;
+ for ( wxString::const_iterator pc = label.begin(); ; ++pc )
+ {
+ if ( pc == label.end() || *pc == _T('\n') )
+ {
+ len = curLine.length();
+ if (len > 0 &&
+ dc.GetPartialTextExtents(curLine, charOffsets))
+ {
+ wxASSERT(charOffsets.GetCount() == len);
+
+ size_t totalWidth = charOffsets.Last();
+ if ( totalWidth > (size_t)maxFinalWidth )
+ {
+ // we need to ellipsize this row
+ int excessPixels = totalWidth - maxFinalWidth +
+ replacementWidth +
+ marginWidth; // security margin (NEEDED!)
+
+ // remove characters in excess
+ size_t initialChar, // index of first char to erase
+ nChars; // how many chars do we need to erase?
+ if (mode == wxELLIPSIZE_START)
+ {
+ initialChar = 0;
+ for (nChars=0;
+ nChars < len && charOffsets[nChars] < excessPixels;
+ nChars++)
+ ;
+ }
+ else if (mode == wxELLIPSIZE_MIDDLE)
+ {
+ // the start & end of the removed span of chars
+ initialChar = len/2;
+ size_t endChar = len/2;
+
+ int removed = 0;
+ for ( ; removed < excessPixels; )
+ {
+ if (initialChar > 0)
+ {
+ // width of the initialChar-th character
+ int width = charOffsets[initialChar] -
+ charOffsets[initialChar-1];
+
+ // remove the initialChar-th character
+ removed += width;
+ initialChar--;
+ }
+
+ if (endChar < len - 1 &&
+ removed < excessPixels)
+ {
+ // width of the (endChar+1)-th character
+ int width = charOffsets[endChar+1] -
+ charOffsets[endChar];
+
+ // remove the endChar-th character
+ removed += width;
+ endChar++;
+ }
+
+ if (initialChar == 0 && endChar == len-1)
+ {
+ nChars = len+1;
+ break;
+ }
+ }
+
+ initialChar++;
+ nChars = endChar - initialChar + 1;
+ }
+ else
+ {
+ wxASSERT(mode == wxELLIPSIZE_END);
+ wxASSERT(len > 0);
+
+ int maxWidth = totalWidth - excessPixels;
+ for (initialChar=0;
+ initialChar < len &&
+ charOffsets[initialChar] < maxWidth;
+ initialChar++)
+ ;
+
+ if (initialChar == 0)
+ {
+ nChars = len;
+ }
+ else
+ {
+ initialChar--; // go back one character
+ nChars = len - initialChar;
+ }
+ }
+
+ if (nChars > len)
+ {
+ // need to remove the entire row!
+ curLine.clear();
+ }
+ else
+ {
+ // erase nChars characters after initialChar (included):
+ curLine.erase(initialChar, nChars+1);
+
+ // if there is space for the replacement dots, add them
+ if (maxFinalWidth > replacementWidth)
+ curLine.insert(initialChar, wxELLIPSE_REPLACEMENT);
+ }
+
+ // if everything was ok, we should have shortened this line
+ // enough to make it fit in maxFinalWidth:
+ wxASSERT(dc.GetTextExtent(curLine).GetWidth() < maxFinalWidth);
+ }
+ }
+
+ // add this (ellipsized) row to the rest of the label
+ ret << curLine;
+ if ( pc == label.end() )
+ {
+ // NOTE: this is the return which always exits the function
+ return ret;
+ }
+ else
+ {
+ ret << *pc;
+ curLine.clear();
+ }
+ }
+ // we need to remove mnemonics from the label for correct calculations
+ else if ( *pc == _T('&') )
+ {
+ // pc+1 is safe: at worst we'll be at end()
+ wxString::const_iterator next = pc + 1;
+ if ( next != label.end() && *next == _T('&') )
+ curLine += _T('&'); // && becomes &
+ //else: remove this ampersand
+ }
+ // we need also to expand tabs to properly calc their size
+ else if ( *pc == _T('\t') )
+ {
+ // Windows natively expands the TABs to 6 spaces. Do the same:
+ curLine += wxT(" ");
+ }
+ else
+ {
+ curLine += *pc;
+ }
+ }
+
+ // this return would generate a
+ // warning C4702: unreachable code
+ // with MSVC since the function always exits from inside the loop
+ //return ret;
+}
+
+wxBorder wxControlBase::GetDefaultBorder() const
+{
+ return wxBORDER_THEME;
+}
+
+