1
$\begingroup$

I have a notebook, nb, on which I want to layer another notebook, di, which has WindowFrame set to "Frameless".

Here's my naive layering attempt just using the same WindowMargins and WindowFrame:

nb = CreateDocument[];
di =
 CreateDocument["",
  WindowSize -> AbsoluteCurrentValue[nb, WindowSize],
  WindowMargins -> AbsoluteCurrentValue[nb, WindowMargins],
  WindowElements -> None,
  WindowFrameElements -> None,
  WindowFrame -> "Frameless",
  WindowOpacity -> .5,
  Background -> Blue
  ]

But we can see it's slightly off:

slight issue

So how do I do this?

$\endgroup$
1
$\begingroup$

Since the frame is "Frameless" the trick is to compute the true WindowSize from the WindowMargins:

trueWindowSize[
   marg : {{_, _}, {_, _}},
   rec : {{_, _}, {_, _}} | Automatic : Automatic
   ] :=
  With[
   {
    sr =
     Replace[rec,
      Automatic :>
       Lookup[
        AbsoluteOptions[$FrontEnd, ScreenRectangle],
        ScreenRectangle
        ]
      ]
    },
   {
    (sr[[1, 2]] - marg[[1, 2]]) -
     (sr[[1, 1]] + marg[[1, 1]]),
    sr[[2, 2]] - marg[[2, 2]] -
     (sr[[2, 1]] + marg[[2, 1]])
    }
   ];
trueWindowSize[
  nb_NotebookObject,
  rec : {{_, _}, {_, _}} | Automatic : Automatic
  ] :=
 trueWindowSize[AbsoluteCurrentValue[nb, WindowMargins], rec]

Then:

nb = CreateDocument[];
di =
 CreateDocument["",
  WindowSize -> trueWindowSize[nb],
  WindowMargins -> AbsoluteCurrentValue[nb, WindowMargins],
  WindowElements -> None,
  WindowFrameElements -> None,
  WindowFrame -> "Frameless",
  WindowOpacity -> .5,
  Background -> Blue
  ]

fixed

Extended Answer:

But there are subtleties here to explore.

To illustrate this, let's compute the WindowSize and WindowMargins for a pile of different window configurations:

windowSize[frame_, elems_, frelems_, close : True | False : True] :=
 
 With[{
   sr =
    Lookup[
     AbsoluteOptions[$FrontEnd, ScreenRectangle],
     ScreenRectangle
     ],
   nb =
    CreateDocument[
     Panel["", Background -> Yellow, ImageSize -> {500, 500}],
     WindowSize -> All,
     WindowFrame -> frame,
     WindowElements -> elems,
     WindowFrameElements -> frelems,
     Visible -> False
     ]},
  If[close,
     NotebookClose[nb];
     <|
      "GivenSize" -> #[WindowSize],
      "TrueSize" -> trueWindowSize[#[WindowMargins], sr]
      |>,
     {nb,
      <|
       "GivenSize" -> #[WindowSize],
       "TrueSize" -> trueWindowSize[#[WindowMargins], sr]
       |>
      }
     ] &@
   Association@
    AbsoluteOptions[nb, {WindowSize, WindowMargins}]
  ]
windowSize[a : {_, _, _}, 
  b : {_, _, _}] :=
 (NotebookClose@*First /@ #; 
    Subtract[#[[1, 2]], #[[2, 2]]]) &@
  {
   windowSize @@ Append[a, False],
   windowSize @@ Append[b, False]
   }

windowSizeData =
  AssociationMap[
   windowSize[#Frame, #Elements, #FrameElements] &,
   AssociationThread[
      {"Frame", "Elements", "FrameElements"},
      #
      ] & /@
    Tuples[
     {
      {"Frameless", "Generic", "ModalDialog", "ModelessDialog", 
       "MovableModalDialog", "Normal", "Palette", "ThinFrame"},
      Subsets[
       {"HorizontalScrollBar", "MagnificationPopUp", "StatusArea", 
        "VerticalScrollBar"}, 1
       ],
      Subsets[
       {"CloseBox", "ZoomBox", "ResizeArea"},
       1
       ]
      }
     ]
   ];

Then we'll group this by discrepancy between stated and real window size:

GroupBy[Normal[windowSizeData],
   (Last[#]["TrueSize"] - Last[#]["GivenSize"] &) -> First] // 
  KeySort // Map[Take[#, 5] &] // Dataset

sample

And we see the WindowSize discrepancy just comes out of the frame. So when we align notebooks we need to account for that. On the other hand, sometimes we may also want to account for in-frame elements, so here's a comparative way to compute size differences based on frame and elements:

windowSizeAdjustments[
   baseStyle :
    {_, _, _} :
    {Automatic, Automatic, Automatic
     },
   newStyle :
    {_, _, _} :
    {"Frameless", None, None}
   ] :=
  windowSizeAdjustments[baseStyle, newStyle] =
   Module[{
     nb =
      CreateDocument[
       Panel["",
        Background -> Yellow,
        ImageSize -> {500, 500}],
       Visible -> False,
       WindowSize -> All,
       WindowFrame -> baseStyle[[1]],
       WindowElements -> baseStyle[[2]],
       WindowFrameElements -> baseStyle[[3]]
       ],
     base,
     frame,
     elem
     },
    base = trueWindowSize[nb];
    SetOptions[nb,
     {
      WindowFrame -> newStyle[[1]],
      WindowFrameElements -> None,
      WindowElements -> None
      }];
    frame =
     trueWindowSize[nb];
    SetOptions[nb,
     {
      WindowFrame -> baseStyle[[1]],
      WindowFrameElements -> newStyle[[2]],
      WindowElements -> newStyle[[3]]
      }];
    elem =
     trueWindowSize[nb];
    NotebookClose[nb];
    <|
     "Elements" -> base - elem,
     "Frame" -> base - frame
     |>
    ];
windowSizeAdjustments[
   nb1 : _Notebook | Automatic : Automatic,
   dialog_Notebook
   ] :=
  Module[{
    opsBase =
     Switch[nb1,
      Automatic,
      {
       WindowFrame -> Automatic,
       WindowElements -> Automatic,
       WindowFrameElements -> Automatic
       },
      _Notebook,
      Association@Join[Options[Notebook], List @@ Rest[nb1]]
      ],
    ops = Association@Join[Options[Notebook], List @@ Rest[dialog]]
    },
   windowSizeAdjustments[
    {
     Lookup[opsBase, WindowFrame, Automatic],
     Lookup[opsBase, WindowFrameElements, Automatic],
     Lookup[opsBase, WindowElements, Automatic]
     },
    {
     Lookup[ops, WindowFrame, "Frameless"],
     Lookup[ops, WindowFrameElements, None],
     Lookup[ops, WindowElements, None]
     }
    ]
   ];

And then we can use this to compute the discrepancy for different notebooks:

nb = Notebook[{}];
di =
  Notebook[{},
   WindowElements -> None,
   WindowFrameElements -> None,
   WindowFrame -> "ThinFrame",
   WindowOpacity -> .5,
   Background -> Blue,
   System`CellInsertionPointCell -> None,
   System`CellInsertionPointColor -> Blue,
   System`BlinkingCellInsertionPoint -> False
   ];
windowSizeAdjustments[nb, di]

<|"Elements" -> {0, 0}, "Frame" -> {-2, 20}|>

And we can make use of this for any frame style (note, beware of the modal frame styles -- you'll have to quit Mathematica to get rid of them, although usually you can say Cancel at the "Save changes to ..." dialog):

NotebookClose /@ {nbObj, diObj};
nbObj = CreateDocument[nb, WindowSize -> {250, 250}];
diObj =
 Block[{frameStyle = "ThinFrame"},
  CreateDocument[di,
   WindowSize ->
    AbsoluteCurrentValue[nbObj, WindowSize] +
     windowSizeAdjustments[nb, Insert[di, WindowFrame -> frameStyle]][
      "Frame"],
   WindowMargins -> AbsoluteCurrentValue[nbObj, WindowMargins],
   WindowFrame -> frameStyle
   ]
  ]

thin frame

NotebookClose /@ {nbObj, diObj};
nbObj = CreateDocument[nb, WindowSize -> {250, 250}];
diObj =
 Block[{frameStyle = "ModelessDialog"},
  CreateDocument[di,
   WindowSize ->
    AbsoluteCurrentValue[nbObj, WindowSize] +
     windowSizeAdjustments[nb, Insert[di, WindowFrame -> frameStyle]][
      "Frame"],
   WindowMargins -> AbsoluteCurrentValue[nbObj, WindowMargins],
   WindowFrame -> frameStyle
   ]
  ]

modeless dialog

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.