wxRTC: added spacing attribute and no-wrap behaviour for table cells.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75105 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart 2013-10-30 15:15:40 +00:00
parent 7bc51afc03
commit 0937367a5d
4 changed files with 226 additions and 34 deletions

View File

@ -304,7 +304,8 @@ enum wxTextBoxAttrFlags
wxTEXT_BOX_ATTR_CLEAR = 0x00000002,
wxTEXT_BOX_ATTR_COLLAPSE_BORDERS = 0x00000004,
wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT = 0x00000008,
wxTEXT_BOX_ATTR_BOX_STYLE_NAME = 0x00000010
wxTEXT_BOX_ATTR_BOX_STYLE_NAME = 0x00000010,
wxTEXT_BOX_ATTR_WHITESPACE = 0x00000020
};
/**
@ -799,7 +800,7 @@ enum wxTextBoxAttrClearStyle
};
/**
Collapse mode styles. TODO: can they be switched on per side?
Collapse mode styles.
*/
enum wxTextBoxAttrCollapseMode
{
@ -818,6 +819,21 @@ enum wxTextBoxAttrVerticalAlignment
wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM = 3
};
/**
Whitespace values mirroring the CSS white-space attribute.
Only wxTEXT_BOX_ATTR_WHITESPACE_NO_WRAP is currently implemented,
in table cells.
*/
enum wxTextBoxAttrWhitespaceMode
{
wxTEXT_BOX_ATTR_WHITESPACE_NONE = 0,
wxTEXT_BOX_ATTR_WHITESPACE_NORMAL = 1,
wxTEXT_BOX_ATTR_WHITESPACE_NO_WRAP = 2,
wxTEXT_BOX_ATTR_WHITESPACE_PREFORMATTED = 3,
wxTEXT_BOX_ATTR_WHITESPACE_PREFORMATTED_LINE = 4,
wxTEXT_BOX_ATTR_WHITESPACE_PREFORMATTED_WRAP = 5
};
/**
@class wxTextAttrBorder
A class representing a rich text object border.
@ -1247,6 +1263,21 @@ public:
*/
bool HasCollapseBorders() const { return HasFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS); }
/**
Returns the whitespace mode.
*/
wxTextBoxAttrWhitespaceMode GetWhitespaceMode() const { return m_whitespaceMode; }
/**
Sets the whitespace mode.
*/
void SetWhitespaceMode(wxTextBoxAttrWhitespaceMode whitespace) { m_whitespaceMode = whitespace; m_flags |= wxTEXT_BOX_ATTR_WHITESPACE; }
/**
Returns @true if the whitespace flag is present.
*/
bool HasWhitespaceMode() const { return HasFlag(wxTEXT_BOX_ATTR_WHITESPACE); }
/**
Returns the vertical alignment.
*/
@ -1493,6 +1524,7 @@ public:
wxTextBoxAttrClearStyle m_clearMode;
wxTextBoxAttrCollapseMode m_collapseMode;
wxTextBoxAttrVerticalAlignment m_verticalAlignment;
wxTextBoxAttrWhitespaceMode m_whitespaceMode;
wxString m_boxStyleName;
};

View File

@ -183,7 +183,9 @@ enum wxTextBoxAttrFlags
wxTEXT_BOX_ATTR_FLOAT = 0x00000001,
wxTEXT_BOX_ATTR_CLEAR = 0x00000002,
wxTEXT_BOX_ATTR_COLLAPSE_BORDERS = 0x00000004,
wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT = 0x00000008
wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT = 0x00000008,
wxTEXT_BOX_ATTR_BOX_STYLE_NAME = 0x00000010,
wxTEXT_BOX_ATTR_WHITESPACE = 0x00000020
};
/**
@ -651,7 +653,7 @@ enum wxTextBoxAttrClearStyle
};
/**
Collapse mode styles. TODO: can they be switched on per side?
Collapse mode styles.
*/
enum wxTextBoxAttrCollapseMode
{
@ -670,6 +672,21 @@ enum wxTextBoxAttrVerticalAlignment
wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM = 3
};
/**
Whitespace values mirroring the CSS white-space attribute.
Only wxTEXT_BOX_ATTR_WHITESPACE_NO_WRAP is currently implemented,
in table cells.
*/
enum wxTextBoxAttrWhitespaceMode
{
wxTEXT_BOX_ATTR_WHITESPACE_NONE = 0,
wxTEXT_BOX_ATTR_WHITESPACE_NORMAL = 1,
wxTEXT_BOX_ATTR_WHITESPACE_NO_WRAP = 2,
wxTEXT_BOX_ATTR_WHITESPACE_PREFORMATTED = 3,
wxTEXT_BOX_ATTR_WHITESPACE_PREFORMATTED_LINE = 4,
wxTEXT_BOX_ATTR_WHITESPACE_PREFORMATTED_WRAP = 5
};
/**
@class wxTextAttrBorder
A class representing a rich text object border.
@ -1094,6 +1111,21 @@ public:
*/
bool HasCollapseBorders() const { return HasFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS); }
/**
Returns the whitespace mode.
*/
wxTextBoxAttrWhitespaceMode GetWhitespaceMode() const { return m_whitespaceMode; }
/**
Sets the whitespace mode.
*/
void SetWhitespaceMode(wxTextBoxAttrWhitespaceMode whitespace) { m_whitespaceMode = whitespace; m_flags |= wxTEXT_BOX_ATTR_WHITESPACE; }
/**
Returns @true if the whitespace flag is present.
*/
bool HasWhitespaceMode() const { return HasFlag(wxTEXT_BOX_ATTR_WHITESPACE); }
/**
Returns the vertical alignment.
*/
@ -1340,6 +1372,7 @@ public:
wxTextBoxAttrClearStyle m_clearMode;
wxTextBoxAttrCollapseMode m_collapseMode;
wxTextBoxAttrVerticalAlignment m_verticalAlignment;
wxTextBoxAttrWhitespaceMode m_whitespaceMode;
wxString m_boxStyleName;
};

View File

@ -5200,6 +5200,14 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
node = node->GetNext();
}
{
// Give the minimum width at least one character width
wxFont font(buffer->GetFontTable().FindFont(attr));
wxCheckSetFont(dc, font);
int charWidth = dc.GetCharWidth();
minWidth = wxMax(charWidth, minWidth);
}
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(minWidth, currentPosition.y + spaceAfterPara));
GetBoxRects(dc, buffer, attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
@ -9880,14 +9888,17 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
wxArrayInt maxUnspecifiedColumnWidths;
maxUnspecifiedColumnWidths.Add(0, m_colCount);
// wxArrayInt percentageColWidthsSpanning(m_colCount);
// These are only relevant when the first column contains spanning information.
// wxArrayInt columnSpans(m_colCount); // Each contains 1 for non-spanning cell, > 1 for spanning cell.
wxArrayInt maxColWidths;
maxColWidths.Add(0, m_colCount);
wxArrayInt minColWidths;
minColWidths.Add(0, m_colCount);
// Separately record the minimum width of columns with
// nowrap cells
wxArrayInt minColWidthsNoWrap;
minColWidthsNoWrap.Add(0, m_colCount);
wxSize tableSize(tableWidth, 0);
int i, j, k;
@ -9895,13 +9906,11 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
for (i = 0; i < m_colCount; i++)
{
absoluteColWidths[i] = 0;
// absoluteColWidthsSpanning[i] = 0;
percentageColWidths[i] = -1;
// percentageColWidthsSpanning[i] = -1;
colWidths[i] = 0;
maxColWidths[i] = 0;
minColWidths[i] = 0;
// columnSpans[i] = 1;
minColWidthsNoWrap[i] = 0;
}
// (0) Determine which cells are visible according to spans
@ -10053,12 +10062,19 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
if (colSpan == 1 && cell->GetMaxSize().x && cell->GetMaxSize().x > maxColWidths[i])
maxColWidths[i] = cell->GetMaxSize().x;
if (cell->GetAttributes().GetTextBoxAttr().HasWhitespaceMode() &&
(cell->GetAttributes().GetTextBoxAttr().GetWhitespaceMode() == wxTEXT_BOX_ATTR_WHITESPACE_NO_WRAP))
{
if (cell->GetMaxSize().x > minColWidthsNoWrap[i])
minColWidthsNoWrap[i] = cell->GetMaxSize().x;
}
}
}
}
}
// (2) Allocate initial column widths from minimum widths, absolute values and proportions
// (2) Allocate initial column widths from absolute values and proportions
for (i = 0; i < m_colCount; i++)
{
if (absoluteColWidths[i] > 0)
@ -10069,8 +10085,6 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
{
colWidths[i] = percentageColWidths[i];
}
else
colWidths[i] = maxUnspecifiedColumnWidths[i];
}
// (3) Process absolute or proportional widths of spanning columns,
@ -10186,18 +10200,45 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
int tableWidthMinusPadding = internalTableWidth - (m_colCount-1)*paddingX;
int widthLeft = tableWidthMinusPadding;
int stretchColCount = 0;
for (i = 0; i < m_colCount; i++)
{
// Subtract min width from width left, then
// add the colShare to the min width
if (colWidths[i] > 0) // absolute or proportional width has been specified
widthLeft -= colWidths[i];
else
{
if (minColWidths[i] > 0)
widthLeft -= minColWidths[i];
bool relaxConstraints = false;
stretchColCount ++;
size_t phase;
for (phase = 0; phase < 2; phase ++)
{
widthLeft = tableWidthMinusPadding;
stretchColCount = 0;
for (i = 0; i < m_colCount; i++)
{
// Subtract min width from width left, then
// add the colShare to the min width
if (colWidths[i] > 0) // absolute or proportional width has been specified
widthLeft -= colWidths[i];
else
{
int minColWidth = wxMax(minColWidths[i], minColWidthsNoWrap[i]);
// If we're at phase 2, it means we had insufficient space, so
// this time, don't take maxUnspecifiedColumnWidths into account
// since we will simply apportion the remaining space.
if (phase == 0)
minColWidth = wxMax(minColWidth, maxUnspecifiedColumnWidths[i]);
if (minColWidth > 0)
widthLeft -= minColWidth;
// Don't allow this to stretch if we're not wrapping; give the space
// to other columns instead.
if (minColWidthsNoWrap[i] == 0)
stretchColCount ++;
}
}
if (widthLeft >= 0)
break;
else if (phase == 0)
{
relaxConstraints = true;
// If there was insufficient space, we're now shrinking to fit the available width.
stretchToFitTableWidth = true;
}
}
@ -10207,6 +10248,23 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
colShare = widthLeft / stretchColCount;
int colShareRemainder = widthLeft - (colShare * stretchColCount);
// Check if any columns will go below their minimum width. If so, give
// up and size columns equally to avoid rendering problems.
if (colShare < 0)
{
for (i = 0; i < m_colCount; i++)
{
int w = colWidths[i];
if (w == 0)
w = wxMax(minColWidths[i], minColWidthsNoWrap[i]);
if ((w + colShare) < minColWidths[i])
{
stretchColCount = 0;
break;
}
}
}
// Check we don't have enough space, in which case shrink all columns, overriding
// any absolute/proportional widths
// TODO: actually we would like to divide up the shrinkage according to size.
@ -10214,33 +10272,61 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
// Could first choose an arbitrary value for stretching cells, and then calculate
// factors to multiply each width by.
// TODO: want to record this fact and pass to an iteration that tries e.g. min widths
bool shareEqually = false;
if (widthLeft < 0 || (stretchToFitTableWidth && (stretchColCount == 0)))
{
colShare = tableWidthMinusPadding / m_colCount;
colShareRemainder = tableWidthMinusPadding - (colShare * m_colCount);
if (stretchColCount == 0)
{
// No columns to stretch or squash, so give up and divide space equally
colShare = tableWidthMinusPadding / m_colCount;
colShareRemainder = tableWidthMinusPadding - (colShare * m_colCount);
shareEqually = true;
}
for (i = 0; i < m_colCount; i++)
{
colWidths[i] = 0;
minColWidths[i] = 0;
}
}
// We have to adjust the columns if either we need to shrink the
// table to fit the parent/table width, or we explicitly set the
// table width and need to stretch out the table.
if (widthLeft < 0 || stretchToFitTableWidth)
for (i = 0; i < m_colCount; i++)
{
for (i = 0; i < m_colCount; i++)
if (colWidths[i] <= 0) // absolute or proportional width has not been specified
{
if (colWidths[i] <= 0) // absolute or proportional width has not been specified
if (widthLeft < 0 || stretchToFitTableWidth)
{
if (minColWidths[i] > 0)
colWidths[i] = minColWidths[i] + colShare;
else
colWidths[i] = colShare;
int minColWidth = wxMax(minColWidths[i], minColWidthsNoWrap[i]);
// Don't use a value for unspecified widths if we have insufficient space,
// unless it's a nowrap cell which is likely to be small.
// Actually this code is useless because if minColWidthsNoWrap exists,
// it'll be the same value as maxUnspecifiedColumnWidths.
if (!relaxConstraints)
minColWidth = wxMax(minColWidth, maxUnspecifiedColumnWidths[i]);
if (minColWidth > 0 && !shareEqually)
colWidths[i] = minColWidth;
// Don't allocate extra space if not wrapping since we assume a tight fit.
// Unless shareEqually forces us to distribute space because we didn't have any
// stretchable columns.
if ((minColWidthsNoWrap[i] == 0) || shareEqually)
colWidths[i] += colShare;
if (i == (m_colCount-1))
colWidths[i] += colShareRemainder; // ensure all pixels are filled
}
else
{
// We're not stretching or shrinking, so calculate the column width
// consistent with how we calculated the remaining table width previously.
int minColWidth = wxMax(minColWidths[i], minColWidthsNoWrap[i]);
minColWidth = wxMax(minColWidth, maxUnspecifiedColumnWidths[i]);
colWidths[i] = minColWidth;
}
}
}
@ -12858,6 +12944,7 @@ void wxTextBoxAttr::Reset()
m_flags = 0;
m_floatMode = wxTEXT_BOX_ATTR_FLOAT_NONE;
m_clearMode = wxTEXT_BOX_ATTR_CLEAR_NONE;
m_whitespaceMode = wxTEXT_BOX_ATTR_WHITESPACE_NONE;
m_collapseMode = wxTEXT_BOX_ATTR_COLLAPSE_NONE;
m_verticalAlignment = wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_NONE;
m_boxStyleName = wxEmptyString;
@ -12881,6 +12968,7 @@ bool wxTextBoxAttr::operator== (const wxTextBoxAttr& attr) const
m_flags == attr.m_flags &&
m_floatMode == attr.m_floatMode &&
m_clearMode == attr.m_clearMode &&
m_whitespaceMode == attr.m_whitespaceMode &&
m_collapseMode == attr.m_collapseMode &&
m_verticalAlignment == attr.m_verticalAlignment &&
@ -12907,6 +12995,7 @@ bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr, bool weakTest) const
(!HasClearMode() && attr.HasClearMode()) ||
(!HasCollapseBorders() && attr.HasCollapseBorders()) ||
(!HasVerticalAlignment() && attr.HasVerticalAlignment()) ||
(!HasWhitespaceMode() && attr.HasWhitespaceMode()) ||
(!HasBoxStyleName() && attr.HasBoxStyleName())))
{
return false;
@ -12923,6 +13012,9 @@ bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr, bool weakTest) const
if (attr.HasVerticalAlignment() && HasVerticalAlignment() && (attr.GetVerticalAlignment() != GetVerticalAlignment()))
return false;
if (attr.HasWhitespaceMode() && HasWhitespaceMode() && (GetWhitespaceMode() != attr.GetWhitespaceMode()))
return false;
if (attr.HasBoxStyleName() && HasBoxStyleName() && (attr.GetBoxStyleName() != GetBoxStyleName()))
return false;
@ -12992,6 +13084,12 @@ bool wxTextBoxAttr::Apply(const wxTextBoxAttr& attr, const wxTextBoxAttr* compar
SetVerticalAlignment(attr.GetVerticalAlignment());
}
if (attr.HasWhitespaceMode())
{
if (!(compareWith && compareWith->HasWhitespaceMode() && compareWith->GetWhitespaceMode() == attr.GetWhitespaceMode()))
SetWhitespaceMode(attr.GetWhitespaceMode());
}
if (attr.HasBoxStyleName())
{
if (!(compareWith && compareWith->HasBoxStyleName() && compareWith->GetBoxStyleName() == attr.GetBoxStyleName()))
@ -13027,6 +13125,9 @@ bool wxTextBoxAttr::RemoveStyle(const wxTextBoxAttr& attr)
if (attr.HasVerticalAlignment())
RemoveFlag(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT);
if (attr.HasWhitespaceMode())
RemoveFlag(wxTEXT_BOX_ATTR_WHITESPACE);
if (attr.HasBoxStyleName())
{
SetBoxStyleName(wxEmptyString);
@ -13127,6 +13228,25 @@ void wxTextBoxAttr::CollectCommonAttributes(const wxTextBoxAttr& attr, wxTextBox
else
absentAttr.AddFlag(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT);
if (attr.HasWhitespaceMode())
{
if (!clashingAttr.HasWhitespaceMode() && !absentAttr.HasWhitespaceMode())
{
if (HasWhitespaceMode())
{
if (GetWhitespaceMode() != attr.GetWhitespaceMode())
{
clashingAttr.AddFlag(wxTEXT_BOX_ATTR_WHITESPACE);
RemoveFlag(wxTEXT_BOX_ATTR_WHITESPACE);
}
}
else
SetWhitespaceMode(attr.GetWhitespaceMode());
}
}
else
absentAttr.AddFlag(wxTEXT_BOX_ATTR_WHITESPACE);
if (attr.HasBoxStyleName())
{
if (!clashingAttr.HasBoxStyleName() && !absentAttr.HasBoxStyleName())

View File

@ -1634,6 +1634,8 @@ bool wxRichTextXMLHelper::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, boo
}
else if (name == wxT("collapse-borders"))
attr.GetTextBoxAttr().SetCollapseBorders((wxTextBoxAttrCollapseMode) wxAtoi(value));
else if (name == wxT("whitespace-mode"))
attr.GetTextBoxAttr().SetWhitespaceMode((wxTextBoxAttrWhitespaceMode) wxAtoi(value));
else if (name.Contains(wxT("border-")))
{
@ -2228,6 +2230,8 @@ wxString wxRichTextXMLHelper::AddAttributes(const wxRichTextAttr& attr, bool isP
if (attr.GetTextBoxAttr().HasCollapseBorders())
AddAttribute(str, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders());
if (attr.GetTextBoxAttr().HasWhitespaceMode())
AddAttribute(str, wxT("whitespace-mode"), (int) attr.GetTextBoxAttr().GetWhitespaceMode());
return str;
}
@ -2705,6 +2709,9 @@ bool wxRichTextXMLHelper::AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, b
if (attr.GetTextBoxAttr().HasCollapseBorders())
AddAttribute(node, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders());
if (attr.GetTextBoxAttr().HasWhitespaceMode())
AddAttribute(node, wxT("whitespace-mode"), (int) attr.GetTextBoxAttr().GetWhitespaceMode());
return true;
}