// Draw the borders and background for the given rectangle and attributes.
// Width and height are taken to be the outer margin size, not the content.
-bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, const wxRichTextAttr& attr, const wxRect& boxRect, int flags)
+bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, const wxRichTextAttr& attr, const wxRect& boxRect, int flags, wxRichTextObject* obj)
{
// Assume boxRect is the area around the content
wxRect marginRect = boxRect;
if (flags & wxRICHTEXT_DRAW_GUIDELINES)
{
- wxRichTextAttr editBorderAttr = attr;
+ wxRichTextAttr editBorderAttr;
// TODO: make guideline colour configurable
editBorderAttr.GetTextBoxAttr().GetBorder().SetColour(*wxLIGHT_GREY);
editBorderAttr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
editBorderAttr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
+ if (obj)
+ {
+ wxRichTextCell* cell = wxDynamicCast(obj, wxRichTextCell);
+ if (cell)
+ {
+ // This ensures that thin lines drawn by adjacent cells (left and above)
+ // don't get overwritten by the guidelines.
+ editBorderAttr.GetTextBoxAttr().GetBorder().GetLeft().Reset();
+ editBorderAttr.GetTextBoxAttr().GetBorder().GetTop().Reset();
+ }
+ }
+
DrawBorder(dc, buffer, editBorderAttr.GetTextBoxAttr().GetBorder(), borderRect, flags);
}
int theseFlags = flags;
if (!GetParent())
theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
- DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags);
+ DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags, this);
if (wxRichTextBuffer::GetFloatingLayoutMode())
DrawFloats(dc, context, range, selection, rect, descent, style);
return obj;
}
+bool wxRichTextParagraphLayoutBox::SetObjectPropertiesWithUndo(wxRichTextObject& obj, const wxRichTextProperties& properties)
+{
+ wxRichTextBuffer* buffer = GetBuffer();
+ wxCHECK_MSG(buffer, false, wxT("Invalid buffer"));
+ wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
+ wxCHECK_MSG(rtc, false, wxT("Invalid rtc"));
+
+ wxRichTextAction* action = NULL;
+ wxRichTextObject* clone = NULL;
+
+#if 1
+ if (rtc->SuppressingUndo())
+ obj.SetProperties(properties);
+ else
+ {
+ clone = obj.Clone();
+ clone->SetProperties(obj.GetProperties());
+ action = new wxRichTextAction(NULL, _("Change Properties"), wxRICHTEXT_CHANGE_OBJECT, buffer, obj.GetParentContainer(), rtc);
+ action->SetOldAndNewObjects(& obj, clone);
+ action->SetPosition(obj.GetRange().GetStart());
+ action->SetRange(obj.GetRange());
+ buffer->SubmitAction(action);
+ }
+#else
+ if (!rtc->SuppressingUndo())
+ {
+ // Create a clone containing the current state of the object. It will be used to Undo the action
+ clone = obj.Clone();
+ clone->SetParent(obj.GetParent());
+ action = new wxRichTextAction(NULL, _("Change Properties"), wxRICHTEXT_CHANGE_OBJECT, buffer, rtc->GetFocusObject(), rtc);
+ action->SetObject(&obj);
+ action->SetPosition(GetRange().GetStart());
+ }
+
+ obj.SetProperties(properties);
+
+ if (!rtc->SuppressingUndo())
+ {
+ buffer->SubmitAction(action);
+ // Finally store the original-state clone; doing so earlier would cause various failures
+ action->StoreObject(clone);
+ }
+#endif
+
+ return true;
+}
+
/// Get the style that is appropriate for a new paragraph at this position.
/// If the previous paragraph has a paragraph style name, look up the next-paragraph
/// style.
{
wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
- // Now draw the table outline, if any, to ensure there are no breaks caused by
- // different-coloured cell dividers overwriting the overall table border.
int colCount = GetColumnCount();
int rowCount = GetRowCount();
int col, row;
if (row == 0 || row == (rowCount-1) || col == 0 || col == (colCount-1))
{
wxRichTextCell* cell = GetCell(row, col);
- if (cell && !cell->GetRange().IsOutside(range))
+ if (cell && cell->IsShown() && !cell->GetRange().IsOutside(range))
{
wxRect childRect(cell->GetPosition(), cell->GetCachedSize());
wxRichTextAttr attr(cell->GetAttributes());
wxRichTextBuffer* buffer = GetBuffer();
wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
- wxPosition position = GetFocusedCell();
- int focusCol = position.GetCol();
- int focusRow = position.GetRow();
- if (focusRow >= startRow && focusRow < (startRow+noRows))
- {
- // Deleting a focused cell causes a segfault later when laying out, due to GetFocusedObject() returning an invalid object
- if ((startRow + noRows) < m_rowCount)
- {
- // There are more rows after the one(s) to be deleted, so set focus in the first of them
- rtc->SetFocusObject(GetCell(startRow + noRows, focusCol));
- }
- else
- {
- // Otherwise set focus in the preceding row
- rtc->SetFocusObject(GetCell(startRow - 1, focusCol));
- }
- }
-
wxRichTextAction* action = NULL;
wxRichTextTable* clone = NULL;
if (!rtc->SuppressingUndo())
// Create a clone containing the current state of the table. It will be used to Undo the action
clone = wxStaticCast(this->Clone(), wxRichTextTable);
clone->SetParent(GetParent());
- action = new wxRichTextAction(NULL, _("Delete row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
+ action = new wxRichTextAction(NULL, _("Delete Row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
action->SetObject(this);
action->SetPosition(GetRange().GetStart());
}
wxRichTextBuffer* buffer = GetBuffer();
wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
- wxPosition position = GetFocusedCell();
- int focusCol = position.GetCol();
- int focusRow = position.GetRow();
- if (focusCol >= startCol && focusCol < (startCol+noCols))
- {
- // Deleting a focused cell causes a segfault later when laying out, due to GetFocusedObject() returning an invalid object
- if ((startCol + noCols) < m_colCount)
- {
- // There are more columns after the one(s) to be deleted, so set focus in the first of them
- rtc->SetFocusObject(GetCell(focusRow, startCol + noCols));
- }
- else
- {
- // Otherwise set focus in the preceding column
- rtc->SetFocusObject(GetCell(focusRow, startCol - 1));
- }
- }
-
wxRichTextAction* action = NULL;
wxRichTextTable* clone = NULL;
if (!rtc->SuppressingUndo())
// Create a clone containing the current state of the table. It will be used to Undo the action
clone = wxStaticCast(this->Clone(), wxRichTextTable);
clone->SetParent(GetParent());
- action = new wxRichTextAction(NULL, _("Delete column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
+ action = new wxRichTextAction(NULL, _("Delete Column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
action->SetObject(this);
action->SetPosition(GetRange().GetStart());
}
wxRichTextBuffer* buffer = GetBuffer();
wxRichTextAction* action = NULL;
wxRichTextTable* clone = NULL;
+
if (!buffer->GetRichTextCtrl()->SuppressingUndo())
{
// Create a clone containing the current state of the table. It will be used to Undo the action
clone = wxStaticCast(this->Clone(), wxRichTextTable);
clone->SetParent(GetParent());
- action = new wxRichTextAction(NULL, _("Add row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
+ action = new wxRichTextAction(NULL, _("Add Row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
action->SetObject(this);
action->SetPosition(GetRange().GetStart());
}
wxRichTextBuffer* buffer = GetBuffer();
wxRichTextAction* action = NULL;
wxRichTextTable* clone = NULL;
+
if (!buffer->GetRichTextCtrl()->SuppressingUndo())
{
// Create a clone containing the current state of the table. It will be used to Undo the action
clone = wxStaticCast(this->Clone(), wxRichTextTable);
clone->SetParent(GetParent());
- action = new wxRichTextAction(NULL, _("Add column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
+ action = new wxRichTextAction(NULL, _("Add Column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
action->SetObject(this);
action->SetPosition(GetRange().GetStart());
}
return false;
}
+bool wxRichTextTableBlock::ComputeBlockForSelection(wxRichTextTable* table, wxRichTextCtrl* ctrl, bool requireCellSelection)
+{
+ if (!ctrl)
+ return false;
+
+ ColStart() = 0;
+ ColEnd() = table->GetColumnCount()-1;
+ RowStart() = 0;
+ RowEnd() = table->GetRowCount()-1;
+
+ wxRichTextSelection selection = ctrl->GetSelection();
+ if (selection.IsValid() && selection.GetContainer() == table)
+ {
+ // Start with an invalid block and increase.
+ wxRichTextTableBlock selBlock(-1, -1, -1, -1);
+ wxRichTextRangeArray ranges = selection.GetRanges();
+ int row, col;
+ for (row = 0; row < table->GetRowCount(); row++)
+ {
+ for (col = 0; col < table->GetColumnCount(); col++)
+ {
+ if (selection.WithinSelection(table->GetCell(row, col)->GetRange().GetStart()))
+ {
+ if (selBlock.ColStart() == -1)
+ selBlock.ColStart() = col;
+ if (selBlock.ColEnd() == -1)
+ selBlock.ColEnd() = col;
+ if (col < selBlock.ColStart())
+ selBlock.ColStart() = col;
+ if (col > selBlock.ColEnd())
+ selBlock.ColEnd() = col;
+
+ if (selBlock.RowStart() == -1)
+ selBlock.RowStart() = row;
+ if (selBlock.RowEnd() == -1)
+ selBlock.RowEnd() = row;
+ if (row < selBlock.RowStart())
+ selBlock.RowStart() = row;
+ if (row > selBlock.RowEnd())
+ selBlock.RowEnd() = row;
+ }
+ }
+ }
+
+ if (selBlock.RowStart() != -1 && selBlock.RowEnd() != -1 && selBlock.ColStart() != -1 && selBlock.ColEnd() != -1)
+ (*this) = selBlock;
+ }
+ else
+ {
+ // See if a whole cell's contents is selected, in which case we can treat the cell as selected.
+ // wxRTC lacks the ability to select a single cell.
+ wxRichTextCell* cell = wxDynamicCast(ctrl->GetFocusObject(), wxRichTextCell);
+ if (cell && (!requireCellSelection || (ctrl->HasSelection() && ctrl->GetSelectionRange() == cell->GetOwnRange())))
+ {
+ int row, col;
+ if (table->GetCellRowColumnPosition(cell->GetRange().GetStart(), row, col))
+ {
+ RowStart() = row;
+ RowEnd() = row;
+ ColStart() = col;
+ ColEnd() = col;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Does this block represent the whole table?
+bool wxRichTextTableBlock::IsWholeTable(wxRichTextTable* table) const
+{
+ return (ColStart() == 0 && RowStart() == 0 && ColEnd() == (table->GetColumnCount()-1) && RowEnd() == (table->GetRowCount()-1));
+}
+
+// Returns the cell focused in the table, if any
+wxRichTextCell* wxRichTextTableBlock::GetFocusedCell(wxRichTextCtrl* ctrl)
+{
+ if (!ctrl)
+ return NULL;
+
+ wxRichTextCell* cell = wxDynamicCast(ctrl->GetFocusObject(), wxRichTextCell);
+ return cell;
+}
+
/*
* Module to initialise and clean up handlers
*/
}
}
+ // We can't rely on the current focus-object remaining valid, if it's e.g. a table's cell.
+ // And we can't cope with this in the calling code: a user may later click in the cell
+ // before deciding to Undo() or Redo(). So play safe and set focus to the buffer.
+ if (m_ctrl)
+ m_ctrl->SetFocusObject(m_buffer, false);
+
// InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
// Layout() would stop prematurely at the top level.
// Invalidate the whole buffer if there were floating objects
else
container->InvalidateHierarchy(GetRange());
- UpdateAppearance(GetPosition());
+ UpdateAppearance(GetPosition(), true);
// TODO: send new kind of modification event