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:
parent
1ea5ef0190
commit
a78618b062
@ -24,6 +24,19 @@
|
||||
|
||||
extern WXDLLIMPEXP_DATA_CORE(const char) wxControlNameStr[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Ellipsize() constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
enum wxEllipsizeFlags
|
||||
{
|
||||
wxELLIPSIZE_PROCESS_MNEMONICS = 1,
|
||||
wxELLIPSIZE_EXPAND_TAB = 2,
|
||||
|
||||
wxELLIPSIZE_DEFAULT_FLAGS = wxELLIPSIZE_PROCESS_MNEMONICS|wxELLIPSIZE_EXPAND_TAB
|
||||
};
|
||||
|
||||
enum wxEllipsizeMode
|
||||
{
|
||||
wxELLIPSIZE_START,
|
||||
@ -77,27 +90,6 @@ public:
|
||||
SetLabel(EscapeMnemonics(text));
|
||||
}
|
||||
|
||||
// static utilities:
|
||||
|
||||
// replaces parts of the string with ellipsis if needed
|
||||
static wxString Ellipsize(const wxString& label, const wxDC& dc,
|
||||
wxEllipsizeMode mode, int maxWidth);
|
||||
|
||||
// get the string without mnemonic characters ('&')
|
||||
static wxString GetLabelText(const wxString& label);
|
||||
|
||||
// removes the mnemonics characters
|
||||
static wxString RemoveMnemonics(const wxString& str);
|
||||
|
||||
// escapes (by doubling them) the mnemonics
|
||||
static wxString EscapeMnemonics(const wxString& str);
|
||||
|
||||
// return the accel index in the string or -1 if none and puts the modified
|
||||
// string into second parameter if non NULL
|
||||
static int FindAccelIndex(const wxString& label,
|
||||
wxString *labelOnly = NULL);
|
||||
|
||||
|
||||
// controls by default inherit the colours of their parents, if a
|
||||
// particular control class doesn't want to do it, it can override
|
||||
// ShouldInheritColours() to return false
|
||||
@ -115,6 +107,30 @@ public:
|
||||
// wxControl-specific processing after processing the update event
|
||||
virtual void DoUpdateWindowUI(wxUpdateUIEvent& event);
|
||||
|
||||
|
||||
|
||||
// static utilities
|
||||
// ----------------
|
||||
|
||||
// replaces parts of the (multiline) string with ellipsis if needed
|
||||
static wxString Ellipsize(const wxString& label, const wxDC& dc,
|
||||
wxEllipsizeMode mode, int maxWidth,
|
||||
int flags = wxELLIPSIZE_DEFAULT_FLAGS);
|
||||
|
||||
// get the string without mnemonic characters ('&')
|
||||
static wxString GetLabelText(const wxString& label);
|
||||
|
||||
// removes the mnemonics characters
|
||||
static wxString RemoveMnemonics(const wxString& str);
|
||||
|
||||
// escapes (by doubling them) the mnemonics
|
||||
static wxString EscapeMnemonics(const wxString& str);
|
||||
|
||||
// return the accel index in the string or -1 if none and puts the modified
|
||||
// string into second parameter if non NULL
|
||||
static int FindAccelIndex(const wxString& label,
|
||||
wxString *labelOnly = NULL);
|
||||
|
||||
protected:
|
||||
// choose the default border for this window
|
||||
virtual wxBorder GetDefaultBorder() const;
|
||||
@ -132,6 +148,11 @@ protected:
|
||||
// initialize the common fields of wxCommandEvent
|
||||
void InitCommandEvent(wxCommandEvent& event) const;
|
||||
|
||||
// Ellipsize() helper:
|
||||
static wxString DoEllipsizeSingleLine(const wxString& label, const wxDC& dc,
|
||||
wxEllipsizeMode mode, int maxWidth,
|
||||
int replacementWidth, int marginWidth);
|
||||
|
||||
// this field contains the label in wx format, i.e. with '&' mnemonics
|
||||
wxString m_labelOrig;
|
||||
|
||||
|
@ -6,14 +6,42 @@
|
||||
// Licence: wxWindows license
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Flags used by wxControl::Ellipsize function.
|
||||
*/
|
||||
enum wxEllipsizeFlags
|
||||
{
|
||||
/// With this flag when calculating the size of the passed string, mnemonics
|
||||
/// characters (see wxControl::SetLabel) will be automatically reduced to a
|
||||
/// single character.
|
||||
/// This leads to correct calculations only if the string passed to Ellipsize()
|
||||
/// will be used with wxControl::SetLabel. If you don't want ampersand to
|
||||
/// be interpreted as mnemonics (e.g. because you use wxControl::SetLabelText)
|
||||
/// then don't use this flag.
|
||||
wxELLIPSIZE_PROCESS_MNEMONICS = 1,
|
||||
|
||||
/// This flag tells wxControl::Ellipsize to calculate the width of tab
|
||||
/// characters @c '\\t' as 6 spaces.
|
||||
wxELLIPSIZE_EXPAND_TAB = 2,
|
||||
|
||||
/// The default flags for wxControl::Ellipsize.
|
||||
wxELLIPSIZE_DEFAULT_FLAGS = wxELLIPSIZE_PROCESS_MNEMONICS|wxELLIPSIZE_EXPAND_TAB
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
The different ellipsization modes supported by the
|
||||
wxControl::Ellipsize function.
|
||||
*/
|
||||
enum wxEllipsizeMode
|
||||
{
|
||||
/// Put the ellipsis at the start of the string, if the string needs ellipsization.
|
||||
wxELLIPSIZE_START,
|
||||
|
||||
/// Put the ellipsis in the middle of the string, if the string needs ellipsization.
|
||||
wxELLIPSIZE_MIDDLE,
|
||||
|
||||
/// Put the ellipsis at the end of the string, if the string needs ellipsization.
|
||||
wxELLIPSIZE_END
|
||||
};
|
||||
|
||||
@ -53,9 +81,12 @@ public:
|
||||
The ellipsization modes. See ::wxEllipsizeMode.
|
||||
@param maxWidth
|
||||
The maximum width of the returned string in pixels.
|
||||
@param flags
|
||||
One or more of the ::wxEllipsize
|
||||
*/
|
||||
static wxString Ellipsize(const wxString& label, const wxDC& dc,
|
||||
wxEllipsizeMode mode, int maxWidth);
|
||||
wxEllipsizeMode mode, int maxWidth,
|
||||
int flags = wxELLIPSIZE_DEFAULT_FLAGS);
|
||||
|
||||
/**
|
||||
Returns the control's text.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user