Skip to main content
added 62 characters in body
Source Link
Kuba
  • 137.7k
  • 13
  • 289
  • 751

Once again b3m2a1 provided more detailed information about FEa FE's feature so I have to retract my claimsclaim that it is not worth an effort to create a popup on cursor position as opposed to e.g. in the corner of the notebook.

The following answer is closely related to Live code templates I'm playing withworking on in a free time.

I will outline two alternative methods, attached cell vs frameless palette. (the linked topic uses the former one but without attaching on a cursor position)

Make sure you saved your work, this is a rough implementation and the second"Cell" approach uses an undocumented AttachedCellAttachedCell.

  • testPopup["Cell"] + Ctrl+1
  • Palette is not clipped by a parent notebook so we don't have to care about that. It matterswhat is very convenient when the selectioncursor is close to the bottom/right edge tooor the menu is not small.

  • Palette notebook is documented

  • AttachedCellAttachedCell can be placed directly put on a cursor position, thanks to an UndocumentedGetSelectionPacket. It is not so easy with Palette because UGSPUndocu... does not account on DockedCellsDockedCells and additionaly we need to do a little WindowMarginsWindowMargins arithmetic.

FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]FrontEndExecute @ FrontEnd`UndocumentedGetSelectionPacket @ InputNotebook[]

its "VirtualSelectionRectangle" value is a cursor position with respect to the bottom left edge of the very bottom docked cell (or a nb menu).

Once again b3m2a1 provided more detailed information about FE feature so I have to retract my claims it is not worth an effort to create a popup on cursor position.

The following answer is closely related to Live code templates I'm playing with.

I will outline two alternative methods, attached cell vs frameless palette. (the linked topic uses the former one but without attaching on cursor position)

Make sure you saved your work, this is a rough implementation and the second approach uses an undocumented AttachedCell.

  • testPopup["Cell"] + Ctrl+1
  • Palette is not clipped by parent notebook so we don't have to care about that. It matters when the selection is close to the bottom/right edge too.

  • Palette is documented

  • AttachedCell can be directly put on cursor position, thanks to UndocumentedGetSelectionPacket. It is not so easy with Palette because UGSP does not account on DockedCells and additionaly we need to do a little WindowMargins arithmetic.

FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]

its "VirtualSelectionRectangle" value is a cursor position with respect to the bottom left edge of the very bottom docked cell (or nb menu).

Once again b3m2a1 provided more detailed information about a FE's feature so I have to retract my claim that it is not worth an effort to create a popup on cursor position as opposed to e.g. in the corner of the notebook.

The following answer is closely related to Live code templates I'm working on in a free time.

I will outline two alternative methods, attached cell vs frameless palette. (the linked topic uses the former one but without attaching on a cursor position)

Make sure you saved your work, this is a rough implementation and the "Cell" approach uses an undocumented AttachedCell.

  • testPopup["Cell"]
  • Palette is not clipped by a parent notebook what is very convenient when the cursor is close to the bottom/right edge or the menu is not small.

  • Palette notebook is documented

  • AttachedCell can be placed directly on a cursor position, thanks to an UndocumentedGetSelectionPacket. It is not easy with Palette because Undocu... does not account on DockedCells and additionaly we need to do WindowMargins arithmetic.

FrontEndExecute @ FrontEnd`UndocumentedGetSelectionPacket @ InputNotebook[]

its "VirtualSelectionRectangle" value is a cursor position with respect to the bottom left edge of the very bottom docked cell (or a nb menu).

added 753 characters in body
Source Link
Kuba
  • 137.7k
  • 13
  • 289
  • 751

Edit

Once again b3m2a1 provided more detailed information about FE feature so I have to retract my claims it is not worth an effort to create a popup on cursor position.

Main

The following answer is closely related to Live code templates I'm playing with.

The linked topic uses AttachedCell but here we will use more documented, notebook with Frameless WindowFrame. I will also not care about preserving definitions or edge casesoutline two alternative methods, if you want take a look at the source in theattached cell vs frameless palette. (the linked topic. uses the former one but without attaching on cursor position)

Run code from the last sectionMake sure you saved your work, run testPopup[]this is a rough implementation and hit Ctrl+1 to interact with menu.

It will be in the center of the notebook. I will explain why in a secsecond approach uses an undocumented AttachedCell.

enter image description here

Cursor position issue

  • Run code from the last section,

  • run testPopup["Palette"]

  • hit Ctrl+1 to interact with menu.

I willThis one is not implement 'show on a cursor position' popupposition because I think it is not worth the effort. I will tell you why and show the direction in case you are stubborn enough.

FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]

enter image description here

with itstough "VirtualSelectionRectangle" it can be used to aquire a little info about cursor position. As I will show now, it:) this one is not enough with respect to other tools we need to use.:

  • testPopup["Cell"] + Ctrl+1

We can either use AttachedCell (undocumented) or a WindowFrame -> Frameless palette for our popup.enter image description here

Cell vs. Palette

  • According to what we know about an AttachedCell 133523. Its position canPalette is not be specifiedclipped by absolute or scaled coordinatesparent notebook so we don't have to care about that. AndIt matters when the offset it supportsselection is only in {-1,1} direction. Not precise enoughclose to use itthe bottom/right edge too.

  • WindowFrame->"Frameless" palette could Palette is documented

  • AttachedCell can be used and if we want to align it with thedirectly put on cursor we needposition, thanks to know parent notebook's WindowMarginsUndocumentedGetSelectionPacket (easy). But coordinates returned fromIt is not so easy with Palette because UndocumentedGetSelectionPacketUGSP dodoes not take into account DockedCells,on DockedCells and additionaly Rasterize[#, "BoundingBox"]& will not help with this as it misses specific margins/frameswe need to do a little WindowMargins arithmetic.

Cursor position

FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]

At this point I decided I don't care. And we didn't even discussed that you need to do many of those calculations Kernel side. And you need to be flexible in case the selectionenter image description here

its "VirtualSelectionRectangle" value is closea cursor position with respect to the bottom.right left edge, then the layout should rise instead of dropthe very bottom docked cell (or nb menu).

testPopup[]testPopup[type:"Cell"|"Palette":"Cell"]:=CreateDocument[{} 
, WindowTitle -> type <> " popup menu"
, StyleDefinitions -> Notebook[{
    Cell[StyleData[StyleDefinitions -> "Default.nb"]],
  Cell[StyleData["Notebook"], Cell[StyleData["Notebook"]
    , NotebookEventActions -> {{"MenuCommand", "InsertNewGraphic"}:>openPopup[]>openPopup[type]} (*Ctrl+1*)
    ]    
  }]
 ]];

items = { 
<|"lbl"->"item 1","action":>NotebookWrite[InputNotebook[], "item1"],"shortkey" -> "m"|>, 
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item2"],"shortkey" -> "k"|>,
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item3"],"shortkey" -> "l"|>
};


openPopup[]openPopup["Palette"]:= NotebookPut @ CenterToParent @ Notebook[
  List @ Cell[BoxData @ ToBoxes @ popupMenu[]popupMenu["Palette"]
  , CellFrameMargins->{{0, 0}, {0, 0}}
  , CellMargins->{{0, 0}, {0, 0}}    
  ]        
, StyleDefinitions->"Dialog.nb"
, WindowClickSelect->False
, WindowFloating->True
, WindowFrame->"Frameless"
, WindowSize->All
, Background->LightBlue
, WindowElements->{}
, WindowFrameElements->{}    
];

popupMenu[]openPopup["Cell"] := Module[{sel,fromTop, fromLeft}
, Catch[
    sel = FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@ 
      InputNotebook[]
  ; If[ 
      MatchQ[sel, KeyValuePattern[{"CellSelectionType" -> "ContentSelection", "SelectionType" -> "CursorRight"}]]
    , {fromLeft,fromTop} = Lookup[sel, "VirtualSelectionRectangle", {{0,0},{0,0}}][[All, 1]]
    , Beep[];Throw@$Canceled
    ]
  ; MathLink`CallFrontEnd[
      FrontEnd`AttachCell[
        EvaluationNotebook[]
      , Cell @ BoxData @ ToBoxes @ popupMenu["Cell"]
      , {Offset[{-fromLeft,-fromTop},0], {Left,Top}}
      , {Left,Top}
      , "ClosingActions"->{ "OutsideMouseClick" }
      ]  
    ]
  ]  
];

popupMenu[type_]:=DynamicModule[
  {item=1,thisObject, parentObject, menuClose, items = items, itemsLength = Length@items}
, Table[With[{i=i},
   EventHandler[#, "MouseEntered":>(item = i)]& @ Button[
     Style[
     StringTemplate["`lbl` (`shortkey`)"]@items[[i]], Bold, FontColor-> Dynamic@If[item==i,Darker@Red,Darker@Green]]
   , items[[i,"action"]]; menuClose[]
  , FrameMargins->15
   , ImageMargins->0
   , Appearance->FrontEndResource["FEExpressions","GrayNinePatchAppearance"]
   ]]
  , {i, itemsLength}
 ]//Column[#,Spacings->0]&
 , Initialization:>(
   If[
     type === "Palette"
   ,
     thisObject = EvaluationNotebook[];
   parentObject  menuClose[]:=NotebookClose @ thisObject
   , 
     thisObject = InputNotebook[];EvaluationCell[];
     menuClose[]:=NotebookClose=NotebookDelete @ thisObject;thisObject
   ];
   parentObject = InputNotebook[];

   
   CurrentValue[parentObject, NotebookEventActions] = {
     "UpArrowKeyDown":>(item=Mod[item-1,itemsLength,1])
   , "DownArrowKeyDown":>(item=Mod[item+1,itemsLength,1])
   , "EscapeKeyDown":>menuClose[]
   , "ReturnKeyDown" :> (items[[item, 2]]; menuClose[])
   , "KeyDown" :> If[
       MemberQ[items[[;;, "shortkey"]], CurrentValue["EventKey"]]
     , (#action& /@ Select[items, #shortkey === CurrentValue["EventKey"]&]);menuClose[]
     ]
   , "MouseClicked" :>  menuClose[] 
  }
)
 , Deinitialization:>(
  CurrentValue[parentObject,NotebookEventActions]=Inherited
)
]


CenterToParent::usage =  "CenterToParent[DialogInput[...]] etc, will make the dialog centered with respect to the parent notebook";

CenterToParent // Attributes = {HoldFirst};

CenterToParent[ dialog_[whatever__, opts : OptionsPattern[]]  ] := With[
    {apc = AbsoluteCurrentValue}
  , With[
        { parentCenter = Transpose @ {
              apc[WindowMargins][[;; , 1]] + .5 apc[ WindowSize]
            , {Automatic, Automatic}
          }
        }
      , dialog[
            whatever
          , NotebookDynamicExpression :> Refresh[
                SetOptions[
                    EvaluationNotebook[]
                  , WindowMargins -> (parentCenter - Transpose[{.5 apc[WindowSize], {0, 0}}])
                  , NotebookDynamicExpression -> None
                ]
              , None
            ]
          , opts 
        ]
     ]
  ];

The following answer is closely related to Live code templates I'm playing with.

The linked topic uses AttachedCell but here we will use more documented, notebook with Frameless WindowFrame. I will also not care about preserving definitions or edge cases, if you want take a look at the source in the linked topic.

Run code from the last section, run testPopup[] and hit Ctrl+1 to interact with menu.

It will be in the center of the notebook. I will explain why in a sec.

enter image description here

Cursor position issue

I will not implement 'show on a cursor position' popup because I think it is not worth the effort. I will tell you why and show the direction in case you are stubborn enough.

FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]

enter image description here

with its "VirtualSelectionRectangle" it can be used to aquire a little info about cursor position. As I will show now, it is not enough with respect to other tools we need to use.

We can either use AttachedCell (undocumented) or a WindowFrame -> Frameless palette for our popup.

  • According to what we know about an AttachedCell 133523. Its position can not be specified by absolute or scaled coordinates. And the offset it supports is only in {-1,1} direction. Not precise enough to use it.

  • WindowFrame->"Frameless" palette could be used and if we want to align it with the cursor we need to know parent notebook's WindowMargins (easy). But coordinates returned from UndocumentedGetSelectionPacket do not take into account DockedCells, additionaly Rasterize[#, "BoundingBox"]& will not help with this as it misses specific margins/frames.

At this point I decided I don't care. And we didn't even discussed that you need to do many of those calculations Kernel side. And you need to be flexible in case the selection is close to the bottom.right edge, then the layout should rise instead of drop.

testPopup[]:=CreateDocument[{},
 StyleDefinitions -> Notebook[{
  Cell[StyleData[StyleDefinitions -> "Default.nb"]],
  Cell[StyleData["Notebook"],
    NotebookEventActions -> {{"MenuCommand", "InsertNewGraphic"}:>openPopup[]} (*Ctrl+1*)
  ]    
 }]
 ]

items = { 
<|"lbl"->"item 1","action":>NotebookWrite[InputNotebook[], "item1"],"shortkey" -> "m"|>, 
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item2"],"shortkey" -> "k"|>,
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item3"],"shortkey" -> "l"|>
};


openPopup[]:= NotebookPut @ CenterToParent @ Notebook[
  List @ Cell[BoxData @ ToBoxes @ popupMenu[]
  , CellFrameMargins->{{0, 0}, {0, 0}}
  , CellMargins->{{0, 0}, {0, 0}}    
  ]        
, StyleDefinitions->"Dialog.nb"
, WindowClickSelect->False
, WindowFloating->True
, WindowFrame->"Frameless"
, WindowSize->All
, Background->LightBlue
, WindowElements->{}
, WindowFrameElements->{}    
];

popupMenu[]:=DynamicModule[
  {item=1,thisObject, parentObject, menuClose, items = items, itemsLength = Length@items}
, Table[With[{i=i},
   EventHandler[#, "MouseEntered":>(item = i)]& @ Button[
     Style[
     StringTemplate["`lbl` (`shortkey`)"]@items[[i]], Bold, FontColor-> Dynamic@If[item==i,Darker@Red,Darker@Green]]
   , items[[i,"action"]]; menuClose[]
  , FrameMargins->15
   , ImageMargins->0
   , Appearance->FrontEndResource["FEExpressions","GrayNinePatchAppearance"]
   ]]
  , {i, itemsLength}
 ]//Column[#,Spacings->0]&
 , Initialization:>(
   thisObject = EvaluationNotebook[];
   parentObject = InputNotebook[];
   menuClose[]:=NotebookClose @ thisObject;
   
   CurrentValue[parentObject, NotebookEventActions] = {
     "UpArrowKeyDown":>(item=Mod[item-1,itemsLength,1])
   , "DownArrowKeyDown":>(item=Mod[item+1,itemsLength,1])
   , "EscapeKeyDown":>menuClose[]
   , "ReturnKeyDown" :> (items[[item, 2]]; menuClose[])
   , "KeyDown" :> If[
       MemberQ[items[[;;, "shortkey"]], CurrentValue["EventKey"]]
     , (#action& /@ Select[items, #shortkey === CurrentValue["EventKey"]&]);menuClose[]
     ]
   , "MouseClicked" :>  menuClose[] 
  }
)
 , Deinitialization:>(
  CurrentValue[parentObject,NotebookEventActions]=Inherited
)
]


CenterToParent::usage =  "CenterToParent[DialogInput[...]] etc, will make the dialog centered with respect to the parent notebook";

CenterToParent // Attributes = {HoldFirst};

CenterToParent[ dialog_[whatever__, opts : OptionsPattern[]]  ] := With[
    {apc = AbsoluteCurrentValue}
  , With[
        { parentCenter = Transpose @ {
              apc[WindowMargins][[;; , 1]] + .5 apc[ WindowSize]
            , {Automatic, Automatic}
          }
        }
      , dialog[
            whatever
          , NotebookDynamicExpression :> Refresh[
                SetOptions[
                    EvaluationNotebook[]
                  , WindowMargins -> (parentCenter - Transpose[{.5 apc[WindowSize], {0, 0}}])
                  , NotebookDynamicExpression -> None
                ]
              , None
            ]
          , opts 
        ]
     ]
  ];

Edit

Once again b3m2a1 provided more detailed information about FE feature so I have to retract my claims it is not worth an effort to create a popup on cursor position.

Main

The following answer is closely related to Live code templates I'm playing with.

I will outline two alternative methods, attached cell vs frameless palette. (the linked topic uses the former one but without attaching on cursor position)

Make sure you saved your work, this is a rough implementation and the second approach uses an undocumented AttachedCell.

  • Run code from the last section,

  • run testPopup["Palette"]

  • hit Ctrl+1 to interact with menu.

This one is not on cursor position because it is tough :) this one is:

  • testPopup["Cell"] + Ctrl+1

enter image description here

Cell vs. Palette

  • Palette is not clipped by parent notebook so we don't have to care about that. It matters when the selection is close to the bottom/right edge too.

  • Palette is documented

  • AttachedCell can be directly put on cursor position, thanks to UndocumentedGetSelectionPacket. It is not so easy with Palette because UGSP does not account on DockedCells and additionaly we need to do a little WindowMargins arithmetic.

Cursor position

FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]

enter image description here

its "VirtualSelectionRectangle" value is a cursor position with respect to the bottom left edge of the very bottom docked cell (or nb menu).

testPopup[type:"Cell"|"Palette":"Cell"]:=CreateDocument[{} 
, WindowTitle -> type <> " popup menu"
, StyleDefinitions -> Notebook[{
    Cell[StyleData[StyleDefinitions -> "Default.nb"]]
  , Cell[StyleData["Notebook"]
    , NotebookEventActions -> {{"MenuCommand", "InsertNewGraphic"}:>openPopup[type]} (*Ctrl+1*)
    ]    
  }]
];

items = { 
<|"lbl"->"item 1","action":>NotebookWrite[InputNotebook[], "item1"],"shortkey" -> "m"|>, 
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item2"],"shortkey" -> "k"|>,
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item3"],"shortkey" -> "l"|>
};


openPopup["Palette"]:= NotebookPut @ CenterToParent @ Notebook[
  List @ Cell[BoxData @ ToBoxes @ popupMenu["Palette"]
  , CellFrameMargins->{{0, 0}, {0, 0}}
  , CellMargins->{{0, 0}, {0, 0}}    
  ]        
, StyleDefinitions->"Dialog.nb"
, WindowClickSelect->False
, WindowFloating->True
, WindowFrame->"Frameless"
, WindowSize->All
, Background->LightBlue
, WindowElements->{}
, WindowFrameElements->{}    
];

openPopup["Cell"] := Module[{sel,fromTop, fromLeft}
, Catch[
    sel = FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@ 
      InputNotebook[]
  ; If[ 
      MatchQ[sel, KeyValuePattern[{"CellSelectionType" -> "ContentSelection", "SelectionType" -> "CursorRight"}]]
    , {fromLeft,fromTop} = Lookup[sel, "VirtualSelectionRectangle", {{0,0},{0,0}}][[All, 1]]
    , Beep[];Throw@$Canceled
    ]
  ; MathLink`CallFrontEnd[
      FrontEnd`AttachCell[
        EvaluationNotebook[]
      , Cell @ BoxData @ ToBoxes @ popupMenu["Cell"]
      , {Offset[{-fromLeft,-fromTop},0], {Left,Top}}
      , {Left,Top}
      , "ClosingActions"->{ "OutsideMouseClick" }
      ]  
    ]
  ]  
];

popupMenu[type_]:=DynamicModule[
  {item=1,thisObject, parentObject, menuClose, items = items, itemsLength = Length@items}
, Table[With[{i=i},
   EventHandler[#, "MouseEntered":>(item = i)]& @ Button[
     Style[
     StringTemplate["`lbl` (`shortkey`)"]@items[[i]], Bold, FontColor-> Dynamic@If[item==i,Darker@Red,Darker@Green]]
   , items[[i,"action"]]; menuClose[]
  , FrameMargins->15
   , ImageMargins->0
   , Appearance->FrontEndResource["FEExpressions","GrayNinePatchAppearance"]
   ]]
  , {i, itemsLength}
 ]//Column[#,Spacings->0]&
 , Initialization:>(
   If[
     type === "Palette"
   ,
     thisObject = EvaluationNotebook[];
     menuClose[]:=NotebookClose @ thisObject
   , 
     thisObject = EvaluationCell[];
     menuClose[]:=NotebookDelete @ thisObject
   ];
   parentObject = InputNotebook[];

   
   CurrentValue[parentObject, NotebookEventActions] = {
     "UpArrowKeyDown":>(item=Mod[item-1,itemsLength,1])
   , "DownArrowKeyDown":>(item=Mod[item+1,itemsLength,1])
   , "EscapeKeyDown":>menuClose[]
   , "ReturnKeyDown" :> (items[[item, 2]]; menuClose[])
   , "KeyDown" :> If[
       MemberQ[items[[;;, "shortkey"]], CurrentValue["EventKey"]]
     , (#action& /@ Select[items, #shortkey === CurrentValue["EventKey"]&]);menuClose[]
     ]
   , "MouseClicked" :>  menuClose[] 
  }
)
 , Deinitialization:>(
  CurrentValue[parentObject,NotebookEventActions]=Inherited
)
]


CenterToParent::usage =  "CenterToParent[DialogInput[...]] etc, will make the dialog centered with respect to the parent notebook";

CenterToParent // Attributes = {HoldFirst};

CenterToParent[ dialog_[whatever__, opts : OptionsPattern[]]  ] := With[
    {apc = AbsoluteCurrentValue}
  , With[
        { parentCenter = Transpose @ {
              apc[WindowMargins][[;; , 1]] + .5 apc[ WindowSize]
            , {Automatic, Automatic}
          }
        }
      , dialog[
            whatever
          , NotebookDynamicExpression :> Refresh[
                SetOptions[
                    EvaluationNotebook[]
                  , WindowMargins -> (parentCenter - Transpose[{.5 apc[WindowSize], {0, 0}}])
                  , NotebookDynamicExpression -> None
                ]
              , None
            ]
          , opts 
        ]
     ]
  ];
deleted 269 characters in body
Source Link
Kuba
  • 137.7k
  • 13
  • 289
  • 751
testPopup[]:=CreateDocument[{},
 StyleDefinitions -> Notebook[{
  Cell[StyleData[StyleDefinitions -> "Default.nb"]],
  Cell[StyleData["Notebook"],
    NotebookEventActions -> {{"MenuCommand", "InsertNewGraphic"}:>openPopup[]} (*Ctrl+1*)
  ]    
 }]
 ]

items = { 
<|"lbl"->"item 1","action":>NotebookWrite[InputNotebook[], "item1"],"shortkey" -> "m"|>, 
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item2"],"shortkey" -> "k"|>,
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item3"],"shortkey" -> "l"|>
};


openPopup[]:=With[
  { pos = Lookup[
      FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]
    , "VirtualSelectionRectangle"
    , False  
  ]
  }
, NotebookPut @ CenterToParent @ Notebook[
    List @ Cell[BoxData @ ToBoxes @ popupMenu[]
    , CellFrameMargins->{{0, 0}, {0, 0}}
    , CellMargins->{{0, 0}, {0, 0}}    
  ]  ]
      
, StyleDefinitions->"Dialog.nb"
, WindowClickSelect->False
, WindowFloating->True
, WindowFrame->"Frameless"
, WindowSize->All
, Background->LightBlue
, WindowElements->{}
, WindowFrameElements->{}
,WindowMargins-> {{Automatic,Automatic},{Automatic,Automatic}}   
]];];

popupMenu[]:=DynamicModule[
  {item=1,thisObject, parentObject, menuClose, items = items, itemsLength = Length@items}
, Table[With[{i=i},
   EventHandler[#, "MouseEntered":>(item = i)]& @ Button[
     Style[
     StringTemplate["`lbl` (`shortkey`)"]@items[[i]], Bold, FontColor-> Dynamic@If[item==i,Darker@Red,Darker@Green]]
   , items[[i,"action"]]; menuClose[]
  , FrameMargins->15
   , ImageMargins->0
   , Appearance->FrontEndResource["FEExpressions","GrayNinePatchAppearance"]
   ]]
  , {i, itemsLength}
 ]//Column[#,Spacings->0]&
 , Initialization:>(
   thisObject = EvaluationNotebook[];
   parentObject = InputNotebook[];
   menuClose[]:=NotebookClose @ thisObject;
   
   CurrentValue[parentObject, NotebookEventActions] = {
     "UpArrowKeyDown":>(item=Mod[item-1,itemsLength,1])
   , "DownArrowKeyDown":>(item=Mod[item+1,itemsLength,1])
   , "EscapeKeyDown":>menuClose[]
   , "ReturnKeyDown" :> (items[[item, 2]]; menuClose[])
   , "KeyDown" :> If[
       MemberQ[items[[;;, "shortkey"]], CurrentValue["EventKey"]]
     , (#action& /@ Select[items, #shortkey === CurrentValue["EventKey"]&]);menuClose[]
     ]
   , "MouseClicked" :>  menuClose[] 
  }
)
 , Deinitialization:>(
  CurrentValue[parentObject,NotebookEventActions]=Inherited
)
]


CenterToParent::usage =  "CenterToParent[DialogInput[...]] etc, will make the dialog centered with respect to the parent notebook";

CenterToParent // Attributes = {HoldFirst};

CenterToParent[ dialog_[whatever__, opts : OptionsPattern[]]  ] := With[
    {apc = AbsoluteCurrentValue}
  , With[
        { parentCenter = Transpose @ {
              apc[WindowMargins][[;; , 1]] + .5 apc[ WindowSize]
            , {Automatic, Automatic}
          }
        }
      , dialog[
            whatever
          , NotebookDynamicExpression :> Refresh[
                SetOptions[
                    EvaluationNotebook[]
                  , WindowMargins -> (parentCenter - Transpose[{.5 apc[WindowSize], {0, 0}}])
                  , NotebookDynamicExpression -> None
                ]
              , None
            ]
          , opts 
        ]
     ]
  ];
testPopup[]:=CreateDocument[{},
 StyleDefinitions -> Notebook[{
  Cell[StyleData[StyleDefinitions -> "Default.nb"]],
  Cell[StyleData["Notebook"],
    NotebookEventActions -> {{"MenuCommand", "InsertNewGraphic"}:>openPopup[]} (*Ctrl+1*)
  ]    
 }]
 ]

items = { 
<|"lbl"->"item 1","action":>NotebookWrite[InputNotebook[], "item1"],"shortkey" -> "m"|>, 
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item2"],"shortkey" -> "k"|>,
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item3"],"shortkey" -> "l"|>
};


openPopup[]:=With[
  { pos = Lookup[
      FrontEndExecute@FrontEnd`UndocumentedGetSelectionPacket@InputNotebook[]
    , "VirtualSelectionRectangle"
    , False  
  ]
  }
, NotebookPut @ CenterToParent @ Notebook[
    List @ Cell[BoxData @ ToBoxes @ popupMenu[]
    , CellFrameMargins->{{0, 0}, {0, 0}}
    , CellMargins->{{0, 0}, {0, 0}}    
    ]
    
, StyleDefinitions->"Dialog.nb"
, WindowClickSelect->False
, WindowFloating->True
, WindowFrame->"Frameless"
, WindowSize->All
, Background->LightBlue
, WindowElements->{}
, WindowFrameElements->{}
,WindowMargins-> {{Automatic,Automatic},{Automatic,Automatic}}
]];

popupMenu[]:=DynamicModule[
  {item=1,thisObject, parentObject, menuClose, items = items, itemsLength = Length@items}
, Table[With[{i=i},
   EventHandler[#, "MouseEntered":>(item = i)]& @ Button[
     Style[
     StringTemplate["`lbl` (`shortkey`)"]@items[[i]], Bold, FontColor-> Dynamic@If[item==i,Darker@Red,Darker@Green]]
   , items[[i,"action"]]; menuClose[]
  , FrameMargins->15
   , ImageMargins->0
   , Appearance->FrontEndResource["FEExpressions","GrayNinePatchAppearance"]
   ]]
  , {i, itemsLength}
 ]//Column[#,Spacings->0]&
 , Initialization:>(
   thisObject = EvaluationNotebook[];
   parentObject = InputNotebook[];
   menuClose[]:=NotebookClose @ thisObject;
   
   CurrentValue[parentObject, NotebookEventActions] = {
     "UpArrowKeyDown":>(item=Mod[item-1,itemsLength,1])
   , "DownArrowKeyDown":>(item=Mod[item+1,itemsLength,1])
   , "EscapeKeyDown":>menuClose[]
   , "ReturnKeyDown" :> (items[[item, 2]]; menuClose[])
   , "KeyDown" :> If[
       MemberQ[items[[;;, "shortkey"]], CurrentValue["EventKey"]]
     , (#action& /@ Select[items, #shortkey === CurrentValue["EventKey"]&]);menuClose[]
     ]
   , "MouseClicked" :>  menuClose[] 
  }
)
 , Deinitialization:>(
  CurrentValue[parentObject,NotebookEventActions]=Inherited
)
]


CenterToParent::usage =  "CenterToParent[DialogInput[...]] etc, will make the dialog centered with respect to the parent notebook";

CenterToParent // Attributes = {HoldFirst};

CenterToParent[ dialog_[whatever__, opts : OptionsPattern[]]  ] := With[
    {apc = AbsoluteCurrentValue}
  , With[
        { parentCenter = Transpose @ {
              apc[WindowMargins][[;; , 1]] + .5 apc[ WindowSize]
            , {Automatic, Automatic}
          }
        }
      , dialog[
            whatever
          , NotebookDynamicExpression :> Refresh[
                SetOptions[
                    EvaluationNotebook[]
                  , WindowMargins -> (parentCenter - Transpose[{.5 apc[WindowSize], {0, 0}}])
                  , NotebookDynamicExpression -> None
                ]
              , None
            ]
          , opts 
        ]
     ]
  ];
testPopup[]:=CreateDocument[{},
 StyleDefinitions -> Notebook[{
  Cell[StyleData[StyleDefinitions -> "Default.nb"]],
  Cell[StyleData["Notebook"],
    NotebookEventActions -> {{"MenuCommand", "InsertNewGraphic"}:>openPopup[]} (*Ctrl+1*)
  ]    
 }]
 ]

items = { 
<|"lbl"->"item 1","action":>NotebookWrite[InputNotebook[], "item1"],"shortkey" -> "m"|>, 
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item2"],"shortkey" -> "k"|>,
<|"lbl"->"item 2","action":>NotebookWrite[InputNotebook[], "item3"],"shortkey" -> "l"|>
};


openPopup[]:= NotebookPut @ CenterToParent @ Notebook[
  List @ Cell[BoxData @ ToBoxes @ popupMenu[]
  , CellFrameMargins->{{0, 0}, {0, 0}}
  , CellMargins->{{0, 0}, {0, 0}}    
  ]        
, StyleDefinitions->"Dialog.nb"
, WindowClickSelect->False
, WindowFloating->True
, WindowFrame->"Frameless"
, WindowSize->All
, Background->LightBlue
, WindowElements->{}
, WindowFrameElements->{}    
];

popupMenu[]:=DynamicModule[
  {item=1,thisObject, parentObject, menuClose, items = items, itemsLength = Length@items}
, Table[With[{i=i},
   EventHandler[#, "MouseEntered":>(item = i)]& @ Button[
     Style[
     StringTemplate["`lbl` (`shortkey`)"]@items[[i]], Bold, FontColor-> Dynamic@If[item==i,Darker@Red,Darker@Green]]
   , items[[i,"action"]]; menuClose[]
  , FrameMargins->15
   , ImageMargins->0
   , Appearance->FrontEndResource["FEExpressions","GrayNinePatchAppearance"]
   ]]
  , {i, itemsLength}
 ]//Column[#,Spacings->0]&
 , Initialization:>(
   thisObject = EvaluationNotebook[];
   parentObject = InputNotebook[];
   menuClose[]:=NotebookClose @ thisObject;
   
   CurrentValue[parentObject, NotebookEventActions] = {
     "UpArrowKeyDown":>(item=Mod[item-1,itemsLength,1])
   , "DownArrowKeyDown":>(item=Mod[item+1,itemsLength,1])
   , "EscapeKeyDown":>menuClose[]
   , "ReturnKeyDown" :> (items[[item, 2]]; menuClose[])
   , "KeyDown" :> If[
       MemberQ[items[[;;, "shortkey"]], CurrentValue["EventKey"]]
     , (#action& /@ Select[items, #shortkey === CurrentValue["EventKey"]&]);menuClose[]
     ]
   , "MouseClicked" :>  menuClose[] 
  }
)
 , Deinitialization:>(
  CurrentValue[parentObject,NotebookEventActions]=Inherited
)
]


CenterToParent::usage =  "CenterToParent[DialogInput[...]] etc, will make the dialog centered with respect to the parent notebook";

CenterToParent // Attributes = {HoldFirst};

CenterToParent[ dialog_[whatever__, opts : OptionsPattern[]]  ] := With[
    {apc = AbsoluteCurrentValue}
  , With[
        { parentCenter = Transpose @ {
              apc[WindowMargins][[;; , 1]] + .5 apc[ WindowSize]
            , {Automatic, Automatic}
          }
        }
      , dialog[
            whatever
          , NotebookDynamicExpression :> Refresh[
                SetOptions[
                    EvaluationNotebook[]
                  , WindowMargins -> (parentCenter - Transpose[{.5 apc[WindowSize], {0, 0}}])
                  , NotebookDynamicExpression -> None
                ]
              , None
            ]
          , opts 
        ]
     ]
  ];
deleted 35 characters in body
Source Link
Kuba
  • 137.7k
  • 13
  • 289
  • 751
Loading
Source Link
Kuba
  • 137.7k
  • 13
  • 289
  • 751
Loading