Make a custom object look like MatrixForm of a matrix?
InterpretationBox
will take care of making safe round trip from boxes to expression but we need to take extra care during condition checking and partition not to evaluate Obj's
arguments.
It does not matter that Obj
is not holding them, Obj
itself can be held. Hold @ Obj[1,2,3,4]
etc.
Edit to the old code
As xzczd has noticed, an Input cell with e.g. Obj[1,2,3,4]
shows explicit MatrixForm
after Ctrl+Shit+N.
Which is strange, the more that I can't reproduce that with combinations of NotebookRead
/MakeExpression
/MakeBoxes
etc.
The problem seems to be caused by TagBox
so we can take even more extra care and work around it:
Obj /: MakeBoxes[
o : Obj[args__], StandardForm
] /; IntegerQ @ Sqrt @ Length @ Unevaluated @ args := With[
{ array = (
List @@@ Partition[Hold[args], Sqrt@Length[Unevaluated[args]]]
) /. Hold[lists__] :> Map[
Function[x, MakeBoxes[x, StandardForm], HoldFirst]
, Unevaluated @ {lists}
, {2}
]
}
, InterpretationBox[
RowBox[{ "(", "\[NoBreak]"
, GridBox[array, RowSpacings -> 1, ColumnSpacings -> 1
, RowAlignments -> Baseline, ColumnAlignments -> Center
]
, "\[NoBreak]", ")"
}]
, o
]
]
Old
Obj /: MakeBoxes[
o : Obj[args__], StandardForm
] /; IntegerQ @ Sqrt @ Length[Unevaluated[args]] := With[
{ matrixFormBoxes = (
List @@@ Partition[Hold[args], Sqrt @ Length[Unevaluated[args]]]
) /. Hold[lists__] :> MakeBoxes[MatrixForm[{lists}]]
}
, InterpretationBox[
matrixFormBoxes
, o
]
]
Obj[1, 2, 3, 4]
Obj[1, 2, 4]
Hold @ Obj[Echo[1], 2, 3, 4, 5, 6, 7, 8, 9]
% // ReleaseHold
% // FullForm
Obj[1,2,3,4,5,6,7,8,9]
related:
https://mathematica.stackexchange.com/a/149668/5478
InterpretationBox
used in answer by J.M. and by Kuba allows you to copy formatted object and keep its proper interpretation as an Obj
expression, but you can't edit such formatted objects. You could make InterpretationBox
editable by using Editable -> True
option but this will allow you to just edit formatted version while interpretation would incorrectly remain unchanged.
To make copied formatted object editable, instead of InterpretationBox
, you could use TemplateBox
with appropriate DisplayFunction
:
Obj // ClearAll
Obj /: MakeBoxes[Obj@args__, StandardForm] := Module[{n, k},
n = Length@Unevaluated@args;
k = Sqrt@n;
TemplateBox[
MakeBoxes /@ Unevaluated@{args},
"Obj",
Tooltip -> "Obj",
DisplayFunction -> (Evaluate@RowBox@{"(", "\[NoBreak]", GridBox[
Partition[Array[Slot, n], k],
RowSpacings -> 1, ColumnSpacings -> 1,
RowAlignments -> Baseline, ColumnAlignments -> Center
], "\[NoBreak]", ")"}&)
] /; IntegerQ@k
]
Example of copying and editing of formatted object:
Obj[1, 2, 3, 4]
Something to start with:
Obj /: MakeBoxes[Obj[args__], form : StandardForm] :=
With[{arr = Partition[{args}, Sqrt[Length[{args}]]]},
With[{boxes = MakeBoxes[MatrixForm[arr], form]},
InterpretationBox[boxes, Obj[args]]]]
I make no attempt to check if the number of arguments is a square number; you can add that check yourself, if you wish.