tdf#170787 Implement matrix creator dialog for Starmath

Dialog is opened through the context menu - formats - matrix and
from the elements menu.

Change-Id: Ia1043e727d797998798ceb60322c6c42d402dce2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198166
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Jenkins
This commit is contained in:
Jan Rheinländer
2026-03-19 10:23:17 +01:00
committed by Noel Grandin
parent 710433d5a6
commit 0c629d277f
12 changed files with 1092 additions and 5 deletions
+1
View File
@@ -44,6 +44,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/smath,\
starmath/uiconfig/smath/ui/smathsettings \
starmath/uiconfig/smath/ui/spacingdialog \
starmath/uiconfig/smath/ui/symdefinedialog \
starmath/uiconfig/smath/ui/matrixeditor \
))
# vim: set noet sw=4 ts=4:
+47
View File
@@ -502,4 +502,51 @@ public:
void SelectChar(sal_Unicode cChar);
};
class MatrixCreatorDialog final : public weld::GenericDialogController
{
std::unique_ptr<weld::Button> mxOk;
std::unique_ptr<weld::Button> mxCancel;
std::unique_ptr<weld::Entry> mxName;
std::unique_ptr<weld::SpinButton> mxRows;
std::unique_ptr<weld::SpinButton> mxCols;
std::unique_ptr<weld::RadioButton> mxUnitMatrix;
std::unique_ptr<weld::RadioButton> mxDiagMatrix;
std::unique_ptr<weld::RadioButton> mxSymmetricMatrix;
std::unique_ptr<weld::RadioButton> mxFullMatrix;
std::unique_ptr<weld::TreeView> mxMatrix;
DECL_LINK(ButtonOkHdl, weld::Button&, void);
DECL_LINK(ButtonCancelHdl, weld::Button&, void);
DECL_LINK(ModifyHdl, weld::Entry&, void);
OUString mOldName;
DECL_LINK(SpinButtonModifyHdl, weld::SpinButton&, void);
DECL_LINK(RadioButtonModifyHdl, weld::Toggleable&, void);
DECL_LINK(MousePressHdl, const MouseEvent&, bool);
int mClickedColumn;
int mEditedColumn;
DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
typedef std::pair<const weld::TreeIter&, OUString> IterString;
DECL_LINK(EditedEntryHdl, const IterString&, bool);
public:
MatrixCreatorDialog(weld::Window *pParent);
virtual ~MatrixCreatorDialog() override;
// Get textual representation of the matrix (including STACK/MATRIX and curly braces
OUString getMatrix() const { return mMatrixText; }
private:
// Get name to be used for filling the matrix (default is "x")
OUString getName() const;
// Change number of rows and/or columns
void resizeMatrix();
// Make matrix diagonal, symmetric, etc.
void shapeMatrix();
// Build matrix in starmath format
OUString buildMatrix() const;
static constexpr int mMaxCols = 10;
OUString mMatrixText;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+2
View File
@@ -76,4 +76,6 @@ class SfxUInt16Item;
#define SID_INLINE_EDIT_ENABLE TypedWhichId<SfxBoolItem>(SID_SMA_START + 131)
#define SID_SAVE_FORMULA (SID_SMA_START + 132)
#define SID_MATRIXEDITOR (SID_SMA_START + 140)
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+1
View File
@@ -254,6 +254,7 @@ inline constexpr OUString RID_UNDOFORMATNAME = u"Format"_ustr;
#define RID_BINOMXY u"binom{<?>}{<?>} "
#define RID_STACK u"stack{<?> # <?> # <?>} "
#define RID_MATRIX u"matrix{<?> # <?> ## <?> # <?>} "
#define RID_MATRIX_DIALOG u".uno:MatrixEditor"
#define RID_ALIGNLX u"alignl <?> "
#define RID_ALIGNCX u"alignc <?> "
#define RID_ALIGNRX u"alignr <?> "
+19 -1
View File
@@ -381,6 +381,24 @@ SfxVoidItem PasteObject SID_PASTEOBJECT
]
SfxVoidItem MatrixEditor SID_MATRIXEDITOR
()
[
AutoUpdate = FALSE,
FastCall = FALSE,
ReadOnlyDoc = TRUE,
Toggle = FALSE,
Container = FALSE,
RecordAbsolute = FALSE,
RecordPerSet;
AccelConfig = FALSE,
MenuConfig = FALSE,
ToolBoxConfig = FALSE,
GroupId = SfxGroupId::Edit;
]
SfxVoidItem PrevError SID_PREVERR
()
[
@@ -578,4 +596,4 @@ SfxVoidItem SaveFormula SID_SAVE_FORMULA
MenuConfig = TRUE,
ToolBoxConfig = TRUE,
GroupId = SfxGroupId::View;
]
]
+5
View File
@@ -208,6 +208,11 @@ interface FormulaView
ExecMethod = Execute ;
StateMethod = GetState ;
]
SID_MATRIXEDITOR //idlpp ole : no , status : no
[
ExecMethod = Execute ;
StateMethod = NoState ;
]
SID_DELETE //idlpp ole : no , status : no
[
ExecMethod = Execute ;
@@ -405,6 +405,7 @@ const SmElementDescr s_a5FormatsList[] =
{RID_BINOMXY, RID_BINOMXY_HELP, {}, {}},
{RID_STACK, RID_STACK_HELP, {}, {}},
{RID_MATRIX, RID_MATRIX_HELP, {}, {}},
{RID_MATRIX_DIALOG, RID_MATRIX_HELP, u"matrix{<?> # <?> ## <?> # <?>} ~ cdot {} cdot {} cdot {}", {}},
};
const SmElementDescr s_a5OthersList[] =
+12 -3
View File
@@ -104,9 +104,18 @@ IMPL_LINK(SmElementsPanel, ElementClickHandler, const OUString&, ElementSource,
{
if (SmViewShell* pViewSh = GetView())
{
SfxStringItem aInsertCommand(SID_INSERTCOMMANDTEXT, ElementSource);
pViewSh->GetViewFrame().GetDispatcher()->ExecuteList(
SID_INSERTCOMMANDTEXT, SfxCallMode::RECORD, { &aInsertCommand });
if (ElementSource == ".uno:MatrixEditor")
{
SfxStringItem aInsertCommand(SID_MATRIXEDITOR);
pViewSh->GetViewFrame().GetDispatcher()->ExecuteList(
SID_MATRIXEDITOR, SfxCallMode::RECORD, { &aInsertCommand });
}
else
{
SfxStringItem aInsertCommand(SID_INSERTCOMMANDTEXT, ElementSource);
pViewSh->GetViewFrame().GetDispatcher()->ExecuteList(
SID_INSERTCOMMANDTEXT, SfxCallMode::RECORD, { &aInsertCommand });
}
}
}
+348
View File
@@ -2187,4 +2187,352 @@ void SmSymDefineDialog::SelectChar(sal_Unicode cChar)
UpdateButtons();
}
MatrixCreatorDialog::MatrixCreatorDialog(weld::Window* pParent)
: GenericDialogController(pParent, "modules/smath/ui/matrixeditor.ui", "MatrixEditor")
, mxOk (m_xBuilder->weld_button("button_ok"))
, mxCancel(m_xBuilder->weld_button("button_cancel"))
, mxName(m_xBuilder->weld_entry("matrixname"))
, mxRows(m_xBuilder->weld_spin_button("num_rows"))
, mxCols(m_xBuilder->weld_spin_button("num_cols"))
, mxUnitMatrix(m_xBuilder->weld_radio_button("unitmatrix"))
, mxDiagMatrix(m_xBuilder->weld_radio_button("diagmatrix"))
, mxSymmetricMatrix(m_xBuilder->weld_radio_button("symmatrix"))
, mxFullMatrix(m_xBuilder->weld_radio_button("fullmatrix"))
, mxMatrix(m_xBuilder->weld_tree_view("matrix"))
, mOldName("x")
, mClickedColumn(-1)
, mEditedColumn(-1)
, mMatrixText("MATRIX{ x_11 # x_12 # x_13 ## x_21 # x_22 # x_23 ## x_31 # x_32 # x_33}")
{
mxOk->connect_clicked(LINK(this, MatrixCreatorDialog, ButtonOkHdl));
mxCancel->connect_clicked(LINK(this, MatrixCreatorDialog, ButtonCancelHdl));
mxName->connect_changed(LINK(this, MatrixCreatorDialog, ModifyHdl));
mxCols->connect_value_changed(LINK(this, MatrixCreatorDialog, SpinButtonModifyHdl));
mxRows->connect_value_changed(LINK(this, MatrixCreatorDialog, SpinButtonModifyHdl));
mxUnitMatrix->connect_toggled(LINK(this, MatrixCreatorDialog, RadioButtonModifyHdl));
mxDiagMatrix->connect_toggled(LINK(this, MatrixCreatorDialog, RadioButtonModifyHdl));
mxSymmetricMatrix->connect_toggled(LINK(this, MatrixCreatorDialog, RadioButtonModifyHdl));
mxFullMatrix->connect_toggled(LINK(this, MatrixCreatorDialog, RadioButtonModifyHdl));
mxMatrix->connect_mouse_press(LINK(this, MatrixCreatorDialog, MousePressHdl));
mxMatrix->connect_editing(LINK(this, MatrixCreatorDialog, EditingEntryHdl), LINK(this, MatrixCreatorDialog, EditedEntryHdl));
mxCols->set_value(3);
mxRows->set_value(3);
mxFullMatrix->set_active(true);
resizeMatrix();
auto xIter = mxMatrix->make_iterator();
int row = 1;
if (mxMatrix->get_iter_first(*xIter))
{
do
{
for (size_t col = 0; col < 3; ++col)
mxMatrix->set_text(*xIter, "x_" + OUString::number(row) + OUString::number(col + 1), col);
++row;
} while (mxMatrix->iter_next(*xIter));
}
shapeMatrix();
}
MatrixCreatorDialog::~MatrixCreatorDialog()
{
}
OUString MatrixCreatorDialog::getName() const
{
OUString result = mxName->get_text();
if (result.isEmpty())
result = "x";
return result;
}
void MatrixCreatorDialog::resizeMatrix()
{
OUString name = getName();
int rows = mxRows->get_value();
int cols = mxCols->get_value();
int oldrows = mxMatrix->n_children();
int oldcols = 0;
if (oldrows > 0)
{
while (oldcols < mMaxCols && mxMatrix->get_sensitive(0, oldcols))
++oldcols;
}
auto xIter = mxMatrix->make_iterator();
if (oldrows > 0 && !mxMatrix->get_iter_first(*xIter))
return;
for (int row = 0; row < std::max(rows, oldrows); ++row)
{
bool newRow = false;
if (row >= oldrows)
{
auto xIterAppend = mxMatrix->make_iterator();
mxMatrix->append(xIterAppend.get());
mxMatrix->copy_iterator(*xIterAppend, *xIter);
newRow = true;
}
else if (row >= rows && row < oldrows)
{
auto xIterRemove = mxMatrix->make_iterator();
mxMatrix->copy_iterator(*xIter, *xIterRemove);
mxMatrix->iter_next(*xIter);
mxMatrix->remove(*xIterRemove);
continue;
}
for (int col = 0; col < std::max(cols, oldcols); ++col)
{
if (col >= oldcols || newRow)
{
mxMatrix->set_text(*xIter, name + "_" + OUString::number(row + 1) + (cols > 1 ? OUString::number(col + 1) : OUString("")), col);
mxMatrix->set_sensitive(*xIter, true, col);
mxMatrix->set_column_visible(col, true);
}
else if (col >= cols && col < oldcols)
{
mxMatrix->set_text(*xIter, "", col);
mxMatrix->set_sensitive(*xIter, false, col);
mxMatrix->set_column_visible(col, false);
}
}
mxMatrix->iter_next(*xIter);
}
mxMatrix->columns_autosize();
// columns_autosize() seems to kill this information
std::vector<bool> editableColumns(mMaxCols, true);
mxMatrix->set_column_editables(editableColumns);
for (int col = cols; col < mMaxCols; ++col)
mxMatrix->set_column_visible(col, false);
}
void MatrixCreatorDialog::shapeMatrix()
{
int rows = mxRows->get_value();
int cols = mxCols->get_value();
if (rows != cols)
return;
auto xIter = mxMatrix->make_iterator();
int row = 0;
if (mxMatrix->get_iter_first(*xIter))
{
do {
for (int col = 0; col < cols; ++col)
{
if (mxUnitMatrix->get_active())
{
if (row == col)
mxMatrix->set_text(*xIter, "1", col);
else
{
mxMatrix->set_text(*xIter, "0", col);
mxMatrix->set_sensitive(*xIter, false, col);
}
} else if (mxDiagMatrix->get_active())
{
if (row != col)
{
mxMatrix->set_text(*xIter, "0", col);
mxMatrix->set_sensitive(*xIter, false, col);
}
} else if (mxSymmetricMatrix->get_active())
{
if (row > col)
{
mxMatrix->set_text(*xIter, mxMatrix->get_text(col, row), col);
mxMatrix->set_sensitive(*xIter, false, col);
}
else
mxMatrix->set_sensitive(*xIter, true, col);
} else if (mxFullMatrix->get_active()) {
mxMatrix->set_sensitive(*xIter, true, col);
}
}
++row;
} while (mxMatrix->iter_next(*xIter));
}
mxMatrix->columns_autosize();
}
OUString MatrixCreatorDialog::buildMatrix() const
{
int rows = mxRows->get_value();
int cols = mxCols->get_value();
bool isVector = (cols == 1);
OUString result = (isVector ? OUString("STACK{") : OUString("MATRIX{"));
for (int row = 0; row < rows; ++row)
{
for (int col = 0; col < cols; ++col)
{
result += mxMatrix->get_text(row, col);
if (col < cols -1)
result += " # ";
}
if (row < rows -1)
{
// Convert STACK format as column vector
if (isVector)
result += " # ";
else
result += " ## ";
}
}
return result + "}";
}
IMPL_LINK_NOARG(MatrixCreatorDialog, ButtonOkHdl, weld::Button&, void)
{
mMatrixText = buildMatrix();
m_xDialog->response(RET_OK);
}
IMPL_LINK_NOARG(MatrixCreatorDialog, ButtonCancelHdl, weld::Button&, void)
{
// Don't set new mMatrixText, thus result of this dialog is ignored
m_xDialog->response(RET_CANCEL);
}
IMPL_LINK(MatrixCreatorDialog, ModifyHdl, weld::Entry&, rEdit, void)
{
OUString newName = rEdit.get_text();
if (newName.isEmpty())
return; // Happens after backspace, before user types a new character
auto xIter = mxMatrix->make_iterator();
if (mxMatrix->get_iter_first(*xIter))
{
do
{
for (sal_Int64 col = 0; col < mxCols->get_value(); ++col)
{
OUString oldText = mxMatrix->get_text(*xIter, col);
if (oldText.startsWith(mOldName))
mxMatrix->set_text(*xIter, newName + oldText.subView(mOldName.getLength()), col);
}
} while (mxMatrix->iter_next(*xIter));
}
mOldName = newName;
}
IMPL_LINK_NOARG(MatrixCreatorDialog, SpinButtonModifyHdl, weld::SpinButton&, void)
{
resizeMatrix();
shapeMatrix(); // Matrix may have become square so that one of the radio buttons takes effect
}
IMPL_LINK_NOARG(MatrixCreatorDialog, RadioButtonModifyHdl, weld::Toggleable&, void)
{
shapeMatrix();
}
namespace {
// Note: The mouse event coordinates are relative to the treeview
int getClickedCell(std::unique_ptr<weld::TreeView>& treeview, const MouseEvent& rMEvt, weld::TreeIter& rIter, const int lastColumn) {
Point mousePos = rMEvt.GetPosPixel();
int column = -1;
bool found = false;
if (treeview->get_iter_first(rIter))
{
do
{
tools::Rectangle rowArea = treeview->get_row_area(rIter);
if ((found = rowArea.Contains(mousePos)))
break;
} while (treeview->iter_next(rIter));
}
else
return -1; // User clicked somewhere else
if (!found)
return -1;
for (int col = -1; col < lastColumn; ++col)
{
tools::Rectangle cellArea = treeview->get_cell_area(rIter, col);
if (cellArea.Contains(mousePos))
{
column = col;
break;
}
}
return column;
}
}
IMPL_LINK(MatrixCreatorDialog, MousePressHdl, const MouseEvent&, rMEvt, bool)
{
if (mEditedColumn > 0)
return false; // Ignore mouse clicks when a cell is being edited
auto xIter = mxMatrix->make_iterator();
mClickedColumn = getClickedCell(mxMatrix, rMEvt, *xIter, mxCols->get_value());
return false; // We don't handle the mouse click, just find the column
}
IMPL_LINK_NOARG(MatrixCreatorDialog, EditingEntryHdl, const weld::TreeIter&, bool)
{
mEditedColumn = mClickedColumn;
return true;
}
IMPL_LINK(MatrixCreatorDialog, EditedEntryHdl, const IterString&, rIterString, bool)
{
if (mEditedColumn < 0)
return false; // Sometimes there is a double call and since we set mEditedColumn to -1 at the end we can avoid that
if (mxSymmetricMatrix->get_active() && mClickedColumn >= 0 && mClickedColumn < mxCols->get_value())
{
auto xIter = mxMatrix->make_iterator();
int clickedRow = 0;
if (!mxMatrix->get_iter_first(*xIter))
return true;
// Which row number did the click occur in?
while (mxMatrix->iter_compare(*xIter, rIterString.first) != 0)
{
++clickedRow;
if (!mxMatrix->iter_next(*xIter))
break;
}
// Sort of complicated, because set_text(row, column, value) seems to have no effect
int row = 0;
mxMatrix->get_iter_first(*xIter);
while (row < mClickedColumn)
{
mxMatrix->iter_next(*xIter);
++row;
}
mxMatrix->set_text(*xIter, rIterString.second, clickedRow);
}
mxMatrix->set_text(rIterString.first, rIterString.second, mEditedColumn); // Required for EditingCanceledHdl()
mEditedColumn = -1;
return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+36
View File
@@ -1531,6 +1531,42 @@ void SmViewShell::Execute(SfxRequest& rReq)
}
break;
case SID_MATRIXEDITOR:
{
auto pMatrixCreatorDialog = std::make_unique<MatrixCreatorDialog>(rReq.GetFrameWeld());
if (pMatrixCreatorDialog->run() == RET_OK)
{
OUString result = pMatrixCreatorDialog->getMatrix();
ESelection eSelection = pWin->GetSelection();
eSelection.Adjust();
auto pEngine = pWin->GetEditEngine();
OUString sText;
for (sal_Int32 p = 0; p < pEngine->GetParagraphCount(); ++p)
{
if (p == eSelection.start.nPara)
{
OUString pText = pEngine->GetText(p);
sText += pText.replaceAt(eSelection.start.nIndex,
eSelection.end.nIndex - eSelection.start.nIndex,
result)
+ "\n";
}
else
sText += pEngine->GetText(p) + "\n";
}
GetDoc()->SetText(sText);
SetStatusText(OUString());
ShowError(nullptr);
GetDoc()->Repaint();
}
}
break;
case SID_DELETE:
if (IsInlineEditEnabled())
{
+1 -1
View File
@@ -233,7 +233,7 @@
<menu:menuitem menu:label="nospace {...}" menu:id=".uno:InsertCommandText?Text:string=nospace {&lt;?&gt;} "/>
<menu:menuitem menu:label="binom x y" menu:id=".uno:InsertCommandText?Text:string=binom{&lt;?&gt;}{&lt;?&gt;} "/>
<menu:menuitem menu:label="stack {...}" menu:id=".uno:InsertCommandText?Text:string=stack{&lt;?&gt; # &lt;?&gt; # &lt;?&gt;} "/>
<menu:menuitem menu:label="matrix {...}" menu:id=".uno:InsertCommandText?Text:string=matrix{&lt;?&gt; # &lt;?&gt; ## &lt;?&gt; # &lt;?&gt;} "/>
<menu:menuitem menu:label="matrix {...}" menu:id=".uno:MatrixEditor"/>
<menu:menuseparator/>
<menu:menuitem menu:label="alignl x" menu:id=".uno:InsertCommandText?Text:string=alignl &lt;?&gt; "/>
<menu:menuitem menu:label="alignc x" menu:id=".uno:InsertCommandText?Text:string=alignc &lt;?&gt; "/>
+619
View File
@@ -0,0 +1,619 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface domain="sm">
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="adjustment_cols">
<property name="lower">1</property>
<property name="upper">10</property>
<property name="value">1</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment_rows">
<property name="lower">1</property>
<property name="upper">100</property>
<property name="value">3</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkListStore" id="matrixmodel">
<columns>
<!-- column-name 1 -->
<column type="gchararray"/>
<!-- column-name 2 -->
<column type="gchararray"/>
<!-- column-name 3 -->
<column type="gchararray"/>
<!-- column-name 4 -->
<column type="gchararray"/>
<!-- column-name 5 -->
<column type="gchararray"/>
<!-- column-name 6 -->
<column type="gchararray"/>
<!-- column-name 7 -->
<column type="gchararray"/>
<!-- column-name 8 -->
<column type="gchararray"/>
<!-- column-name 9 -->
<column type="gchararray"/>
<!-- column-name 10 -->
<column type="gchararray"/>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name weight1 -->
<column type="gint"/>
<!-- column-name weight2 -->
<column type="gint"/>
<!-- column-name weight3 -->
<column type="gint"/>
<!-- column-name weight4 -->
<column type="gint"/>
<!-- column-name weight5 -->
<column type="gint"/>
<!-- column-name weight6 -->
<column type="gint"/>
<!-- column-name weight7 -->
<column type="gint"/>
<!-- column-name weight8 -->
<column type="gint"/>
<!-- column-name weight9 -->
<column type="gint"/>
<!-- column-name weight10 -->
<column type="gint"/>
<!-- column-name sensitive1 -->
<column type="gboolean"/>
<!-- column-name sensitive2 -->
<column type="gboolean"/>
<!-- column-name sensitive3 -->
<column type="gboolean"/>
<!-- column-name sensitive4 -->
<column type="gboolean"/>
<!-- column-name sensitive5 -->
<column type="gboolean"/>
<!-- column-name sensitive6 -->
<column type="gboolean"/>
<!-- column-name sensitive7 -->
<column type="gboolean"/>
<!-- column-name sensitive8 -->
<column type="gboolean"/>
<!-- column-name sensitive9 -->
<column type="gboolean"/>
<!-- column-name sensitive10 -->
<column type="gboolean"/>
</columns>
</object>
<object class="GtkDialog" id="MatrixEditor">
<property name="width-request">800</property>
<property name="height-request">600</property>
<property name="can-focus">False</property>
<property name="border-width">6</property>
<property name="title" translatable="yes" context="matrixeditor|MatrixEditorDialog">Matrix Editor</property>
<property name="type-hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox3">
<property name="can-focus">False</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="hexpand">True</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area3">
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="button_ok">
<property name="label" translatable="yes" context="stock">_OK</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="has-default">True</property>
<property name="receives-default">True</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_cancel">
<property name="label" translatable="yes" context="stock">_Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="has-default">True</property>
<property name="receives-default">True</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">24</property>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="margin-start">12</property>
<property name="margin-top">6</property>
<property name="label-xalign">0</property>
<property name="shadow-type">none</property>
<child>
<!-- n-columns=2 n-rows=7 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="margin-start">12</property>
<property name="margin-top">6</property>
<property name="row-spacing">3</property>
<property name="column-spacing">6</property>
<child>
<object class="GtkLabel" id="label_columns">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" context="matrixeditor|Columns">Columns:</property>
<accessibility>
<relation type="label-for" target="num_cols"/>
</accessibility>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="num_cols">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="max-width-chars">2</property>
<property name="text">2</property>
<property name="adjustment">adjustment_cols</property>
<property name="climb-rate">1</property>
<property name="value">1</property>
<accessibility>
<relation type="labelled-by" target="label_columns"/>
</accessibility>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_rows">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" context="matrixeditor|Rows">Rows:</property>
<accessibility>
<relation type="label-for" target="num_rows"/>
</accessibility>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="num_rows">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="hexpand">True</property>
<property name="max-width-chars">3</property>
<property name="text">3</property>
<property name="adjustment">adjustment_rows</property>
<property name="climb-rate">1</property>
<property name="value">3</property>
<accessibility>
<relation type="labelled-by" target="label_rows"/>
</accessibility>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_name">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" context="matrixeditor|Name">Name:</property>
<accessibility>
<relation type="label-for" target="matrixname"/>
</accessibility>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="matrixname">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="hexpand">True</property>
<property name="width-chars">5</property>
<property name="text">x</property>
<accessibility>
<relation type="labelled-by" target="label_name"/>
</accessibility>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="unitmatrix">
<property name="label" translatable="yes" context="matrixeditor|UnitMatrix">Unit matrix</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="margin-start">18</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">fullmatrix</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="diagmatrix">
<property name="label" translatable="yes" context="matrixeditor|DiagonalMatrix">Diagonal matrix</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="margin-start">18</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">fullmatrix</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="symmatrix">
<property name="label" translatable="yes" context="matrixeditor|SymmetrixMatrix">Symmetric matrix</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="margin-start">18</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">fullmatrix</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="fullmatrix">
<property name="label" translatable="yes" context="matrixeditor|FullMatrix">Full matrix</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="margin-start">18</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">6</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes" context="matrixeditor|Properties">Properties</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="width-request">600</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="matrix">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="model">matrixmodel</property>
<property name="headers-visible">False</property>
<property name="enable-search">False</property>
<property name="search-column">0</property>
<property name="show-expanders">False</property>
<property name="enable-grid-lines">both</property>
<property name="enable-tree-lines">True</property>
<child>
<object class="GtkTreeViewColumn" id="col1">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">1</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text1">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">21</attribute>
<attribute name="text">0</attribute>
<attribute name="weight">11</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col2">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">2</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text2">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">22</attribute>
<attribute name="text">1</attribute>
<attribute name="weight">12</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col3">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">3</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text3">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">23</attribute>
<attribute name="text">2</attribute>
<attribute name="weight">13</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col4">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">4</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text4">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">24</attribute>
<attribute name="text">3</attribute>
<attribute name="weight">14</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col5">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">5</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text5">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">25</attribute>
<attribute name="text">4</attribute>
<attribute name="weight">15</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col6">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">6</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text6">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">26</attribute>
<attribute name="text">5</attribute>
<attribute name="weight">16</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col7">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">7</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text7">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">27</attribute>
<attribute name="text">6</attribute>
<attribute name="weight">17</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col8">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">8</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text8">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">28</attribute>
<attribute name="text">7</attribute>
<attribute name="weight">18</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col9">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">9</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text9">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">29</attribute>
<attribute name="text">8</attribute>
<attribute name="weight">19</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col10">
<property name="sizing">autosize</property>
<property name="min-width">75</property>
<property name="title">10</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="text10">
<property name="alignment">center</property>
<property name="editable">True</property>
</object>
<attributes>
<attribute name="sensitive">30</attribute>
<attribute name="text">9</attribute>
<attribute name="weight">20</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-5">button_ok</action-widget>
<action-widget response="-5">button_cancel</action-widget>
</action-widgets>
<child internal-child="accessible">
<object class="AtkObject" id="MatrixEditor-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="matrixeditor|extended_tip|MatrixEditorDialog">You can edit a vector or a matrix.</property>
</object>
</child>
</object>
</interface>