split wxControl::Ellipsize() in two functions for better readability of the code; add support for ellipsization flags which allow to disable special processing of TAB/mnemonics characters

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58759 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2009-02-08 12:56:14 +00:00
parent 1ea5ef0190
commit a78618b062
3 changed files with 237 additions and 148 deletions

View File

@@ -212,137 +212,178 @@ int wxControlBase::FindAccelIndex(const wxString& label, wxString *labelOnly)
return indexAccel;
}
wxBorder wxControlBase::GetDefaultBorder() const
{
return wxBORDER_THEME;
}
// ----------------------------------------------------------------------------
// wxControlBase - ellipsization code
// ----------------------------------------------------------------------------
#define wxELLIPSE_REPLACEMENT wxT("...")
/* static and protected */
wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxDC& dc,
wxEllipsizeMode mode, int maxFinalWidth,
int replacementWidth, int marginWidth)
{
wxASSERT_MSG(replacementWidth > 0 && marginWidth > 0,
"Invalid parameters");
wxASSERT_MSG(!curLine.Contains('\n'),
"Use Ellipsize() instead!");
// NOTE: this function assumes that any mnemonic/tab character has already
// been handled if it was necessary to handle them (see Ellipsize())
if (maxFinalWidth <= 0)
return wxEmptyString;
wxArrayInt charOffsets;
size_t len = curLine.length();
if (len == 0 ||
!dc.GetPartialTextExtents(curLine, charOffsets))
return curLine;
wxASSERT(charOffsets.GetCount() == len);
size_t totalWidth = charOffsets.Last();
if ( totalWidth <= (size_t)maxFinalWidth )
return curLine; // we don't need to do any ellipsization!
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?
switch (mode)
{
case wxELLIPSIZE_START:
initialChar = 0;
for (nChars=0;
nChars < len && charOffsets[nChars] < excessPixels;
nChars++)
;
break;
case 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;
}
break;
case 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;
}
}
break;
default:
wxFAIL_MSG("invalid ellipsize mode");
}
wxString ret(curLine);
if (nChars >= len)
{
// need to remove the entire row!
ret.clear();
}
else
{
// erase nChars characters after initialChar (included):
ret.erase(initialChar, nChars+1);
// if there is space for the replacement dots, add them
if (maxFinalWidth > replacementWidth)
ret.append(wxELLIPSE_REPLACEMENT);//.insert(initialChar, wxELLIPSE_REPLACEMENT);
}
// if everything was ok, we should have shortened this line
// enough to make it fit in maxFinalWidth:
wxASSERT(dc.GetTextExtent(ret).GetWidth() < maxFinalWidth);
return ret;
}
/* static */
wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc,
wxEllipsizeMode mode, int maxFinalWidth)
wxEllipsizeMode mode, int maxFinalWidth,
int flags)
{
wxArrayInt charOffsets;
wxString ret;
// these cannot be cached as they can change because of e.g. a font change
// these cannot be cached between different Ellipsize() calls as they can
// change because of e.g. a font change; however we calculate them only once
// when ellipsizing multiline labels:
int replacementWidth = dc.GetTextExtent(wxELLIPSE_REPLACEMENT).GetWidth();
int marginWidth = dc.GetCharWidth()*2;
int marginWidth = dc.GetCharWidth();
// 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') )
if ( pc == label.end() || *pc == wxS('\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);
}
}
curLine = DoEllipsizeSingleLine(curLine, dc, mode, maxFinalWidth,
replacementWidth, marginWidth);
// add this (ellipsized) row to the rest of the label
ret << curLine;
@@ -358,19 +399,19 @@ wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc,
}
}
// we need to remove mnemonics from the label for correct calculations
else if ( *pc == _T('&') )
else if ( *pc == wxS('&') && (flags & wxELLIPSIZE_PROCESS_MNEMONICS) != 0 )
{
// 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 &
if ( next != label.end() && *next == wxS('&') )
curLine += wxS('&'); // && becomes &
//else: remove this ampersand
}
// we need also to expand tabs to properly calc their size
else if ( *pc == _T('\t') )
else if ( *pc == wxS('\t') && (flags & wxELLIPSIZE_EXPAND_TAB) != 0 )
{
// Windows natively expands the TABs to 6 spaces. Do the same:
curLine += wxT(" ");
curLine += wxS(" ");
}
else
{
@@ -384,10 +425,6 @@ wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc,
//return ret;
}
wxBorder wxControlBase::GetDefaultBorder() const
{
return wxBORDER_THEME;
}
// ----------------------------------------------------------------------------