# Correct arithmetics for CellMargins, CellFrame and CellFrameMargins

When writing this answer I came into trouble trying to calculate total horizontal margins for contents of a cell in the right way. The first part of the problem is that both CellMargins and CellFrameMargins can be explicitly specified in two ways:

Possible settings are:

1. dist the same margins on all sides
2. {{left,right},{bottom,top}} different margins on different sides

With the first specification I have to double the value of the option, with the second I have to take the first element of the list and then sum up the values. Of course I can write a function which will handle both situations separately, but may be there is an elegant way to avoid this?

The second part of the problem is that the value of CellFrameMargins is used only if the corresponding value of CellFrame is True or a numeric nonzero. And all the numeric values are allowed to be negative. Here is a simple setup for playing with these options:

cell = Notebook[{Cell[StringJoin[Table["abcd ", {20}]]]},
PageWidth -> 600,
CellMargins -> {{200, 200}, {10, 10}},
CellFrame -> {{True, True}, {True, True}},
CellFrameMargins -> {{20, 20}, {10, 10}}];
Rasterize[cell, "Image"]
% // ImageDimensions


{200, 84}


Currently the best I come up with is the following:

margins = Total[Replace[
Switch[CurrentValue[{CellFrame, 1}],
True | {True, True}, {CurrentValue[{CellMargins, 1}], CurrentValue[{CellFrameMargins, 1}]},
_?NumericQ | {_?NumericQ, _?NumericQ}, {CurrentValue[{CellMargins, 1}], CurrentValue[{CellFrameMargins, 1}]*Sign[Abs[CurrentValue[{CellFrame, 1}]]], CurrentValue[{CellFrame, 1}]},
_, {CurrentValue[{CellMargins, 1}]}], {x_?NumericQ :> 2 x, l_List :> Total[l]}, {1}]]


This solution is already ugly and complicated but still doesn't handle correctly mixed specifications like CellFrame -> {{1, True}, {1, 1}}. And my final intention is to use it in Dynamic where the above simple forms of CurrentValue should be replaced with CurrentValue[EvaluationNotebook[], {StyleDefinitions, "Input", CellFrame}] etc.

Is there a better way to get the complete margins?

It seems the best way is to lead to the canonical form {{_, _}, {_, _}} every option on the first step, then handle their inter-dependencies separately. The following module returns complete horizontal and vertical margins {mHor, mVert} for "Input" style:

Module[{m, f, fm},
{m, f, fm} = CurrentValue[EvaluationNotebook[], {StyleDefinitions, "Input", #}] & /@ {CellMargins, CellFrame, CellFrameMargins};
(* canonicalization *)
{m, f, fm} = Replace[{m, f, fm}, x : Except[{{_, _}, {_, _}}] :> {{x, x}, {x, x}}, {1}];
(* replacing CellFrameMargins by zeros where the frame is off *)
fm = ReplacePart[fm, Position[f, Except[True | _?(Positive[Abs[#]] &)], {2}, Heads -> False] -> 0];
(* clearing up non-numeric values *)
{m, f, fm} = Replace[{m, f, fm}, x_ /; Not@NumericQ[x] :> 0, {3}];
Total /@ (m + f + fm)]

{76, 15}


Note that the above implementation is still incomplete because it doesn't take into account CellLabelMargins and CellFrameLabelMargins as well as "Widths" suboption of CellBracketOptions.