Maple's Standard GUI has context-sensitive menus. Those are the menus that appear when one right-clicks on a output (or input, in a Dcoument).
Those context-menus can be customized.
Below is an example which adds a new submenu. The new submenu is populated automatically according to the types of thing found within the object itself.
It's an alternative to a menu-item that already exists, which shows up as "Help on Command". But that existing item only comes up if the object is a function call, and only allows for a single help-page to get displayed. This alternative submenu gets populated with a dynamic number of entries (according to what is found in the object).
restart:
with(ContextMenu):
newCM := CurrentContext[Copy]():
tset := proc(t)
Typesetting:-mover(
Typesetting:-mo("→"),
Typesetting:-mrow(
Typesetting:-mi("Help"),
Typesetting:-mo("⁢"),
Typesetting:-mi("on"),
Typesetting:-mo("⁢"),
Typesetting:-mtext(t)
));
end proc:
newCM[EntryGenerators][Add]( "Help Topics",
proc(e)
local x, f;
f:=proc(t)
local s;
if not type(t,'And'(name,constant)) then
op(0,t);
end if;
end proc:
[seq([ convert(x, 'string'), [x] ],
x=subs([':-Fraction'=NULL,Int=int],
map(f,indets(e,algebraic))
minus {':-Float',':-Integer',symbol,`+`,`-`,`*`,`/`} ))];
end proc);
newCM:-Queries:-Add(
"Is Help Constant",
proc(t)
if hastype(t,'And'(name,constant)) then
true;
else
false;
end if;
end proc):
newCM:-Queries:-Add(
"Is Help ArithOp",
proc(t)
if {`+`,`-`,`*`,`/`} minus map(x->op(0,x),indets(t,algebraic)) <> {} then
true;
else
false;
end if;
end proc):
newCM[Entries][Add]("Help ( related )",
"proc(t) print(INTERFACE_HELP(':-display',':-topic'=%ARG1)); t; end proc(%EXPR)",
algebraic,
'entry_generator'="Help Topics",
'operator'=tset("%ARG1"),
'helpstring'="Help on select subtopic"
):
newCM[Entries][Add]("Pi, gamma, Catalan",
"proc(t) print(INTERFACE_HELP(':-display',':-topic'=constant)); t; end proc(%EXPR)",
algebraic,
'test'="Is Help Constant",
'operator'=tset("constants"),
'helpstring'="Help on special constants",
'submenu'=["Help ( related )"]
):
newCM[Entries][Add]("`+`,`-`,`*`,`/`",
"proc(t) print(INTERFACE_HELP(':-display',':-topic'=`+`)); t; end proc(%EXPR)",
algebraic,
'test'="Is Help ArithOp",
'operator'=tset("arithmetic"),
'helpstring'="Help on arithmetic operators",
'submenu'=["Help ( related )"]
):
Install(newCM);
newCM:-Entries:-Enable("Help ( related )");
# Right-click on the output of this below (or on it
# as input, in a Document)
Int((1/7)*sqrt(Pi*gamma)-GAMMA(x)*sin(x), x);
# The new entries can be disabled, preventing them
# from appearing.
#newCM:-Entries:-Disable("Help ( related )");
See the ?ContextMenu help-pages for more details.
There are a few things which could make the context-menu system more powerful:
The Maple experts will recognize the procedure which does the extraction of candidate help-topics from the object. Improvements to this are most welcome.
On the topic of improvement, a right-click menuing system available from the GUI's white background (no object involved) would be much more modern than the current top-bar menu system.
There are other things that can be done with customized context menus. Here are a few below.
restart:
with(ContextMenu):
# procedure used to form 2D Math for display over context-menu
# action arrows when performed in a Document.
ts := proc(x) Typesetting:-mover(Typesetting:-mo("→"),Typesetting:-mtext(x)) end proc:
newCM := CurrentContext[Copy](): # New():
# Some test queries, to be used in defns of new entries.
newCM:-Queries:-Add(
"Is Procedure Not Stopat",
proc(t)
if type(t,`procedure`)
and not member(t,:-stopat()) then
true;
else
false;
end if;
end proc
):
newCM:-Queries:-Add(
"Is Procedure Stopat",
proc(t)
if type(t,`procedure`)
and member(t,:-stopat()) then
true;
else
false;
end if;
end proc
):
# The new context-menu entries.
newCM[Entries][Add](
"print",
"print(%EXPR)",
`procedure`,
'helpstring'="print/eval procedure",
'operator'=ts("print"),
'category'="Category 1",
'submenu'=["procedure"],
NULL
):
newCM[Entries][Add](
"parameters",
"op(1,eval(%EXPR))",
`procedure`,
'helpstring'="procedure parameter sequence",
'operator'=ts("parameters"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"locals",
"op(2,eval(%EXPR))",
`procedure`,
'helpstring'="procedure locals",
'operator'=ts("locals"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"options",
"op(3,eval(%EXPR))",
`procedure`,
'helpstring'="procedure options",
'operator'=ts("options"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"remember table",
"op(4,eval(%EXPR))",
`procedure`,
'helpstring'="procedure remember table",
'operator'=ts("remember table"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"description",
"op(5,eval(%EXPR))",
`procedure`,
'helpstring'="procedure description sequence",
'operator'=ts("description"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"globals",
"op(6,eval(%EXPR))",
`procedure`,
'helpstring'="procedure globals",
'operator'=ts("globals"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"lexicals",
"op(7,eval(%EXPR))",
`procedure`,
'helpstring'="procedure lexical table",
'operator'=ts("lexicals"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"return type",
"op(8,eval(%EXPR))",
`procedure`,
'helpstring'="procedure return type",
'operator'=ts("return type"),
'category'="Category 1",
'submenu'=["procedure", "operands"],
NULL
):
newCM[Entries][Add](
"compile",
"Compiler:-Compile(%EXPR)",
`procedure`,
'autoassign'=true,
'helpstring'="compile procedure",
'operator'=ts("compile"),
'category'="Category 1",
'submenu'=["procedure"],
NULL
):
newCM[Entries][Add](
"remember table",
"op(4,eval(%EXPR))",
`procedure`,
'helpstring'="return procedure's remember table",
'operator'=ts("remember table"),
'category'="Category 1",
'submenu'=["procedure"],
NULL
):
newCM[Entries][Add](
"dismantle",
"dismantle(%EXPR)",
anything,
'helpstring'="dismantle expression",
'operator'=ts("dismantle"),
'submenu'=["hackware"],
NULL
):
newCM[Entries][Add](
"memory address",
"addressof(%EXPR)",
anything,
'helpstring'="memory address of expression",
'operator'=ts("addressof"),
'submenu'=["hackware"],
NULL
):
newCM[Entries][Add](
"active to inert representation",
"ToInert(%EXPR)",
anything,
'helpstring'="convert to inert representation of expression",
'operator'=ts("ToInert"),
'submenu'=["hackware"],
NULL
):
newCM[Entries][Add](
"inert to active representation",
"FromInert(%EXPR)",
anything,
'helpstring'="convert from inert to active representation of expression",
'operator'=ts("FromInert"),
'submenu'=["hackware"],
NULL
):
newCM[Entries][Add](
"set trace",
"trace(%EXPR)",
`procedure`,
'helpstring'="set procedure to trace",
'operator'=ts("trace"),
'submenu'=["hackware"],
NULL
):
newCM[Entries][Add](
"unset trace",
"untrace(%EXPR)",
`procedure`,
'helpstring'="unset procedure to trace",
'operator'=ts("untrace"),
'submenu'=["hackware"],
NULL
):
# Now add entries whose presence involves a test more complicated
# than merely a type-check.
newCM[Entries][Add](
"set debug",
"stopat(%EXPR)",
`procedure`,
'test'="Is Procedure Not Stopat",
'helpstring'="set procedure to debug",
'operator'=ts("stopat"),
'submenu'=["hackware"],
NULL
):
newCM[Entries][Add](
"unset debug",
"unstopat(%EXPR)",
`procedure`,
'test'="Is Procedure Stopat",
'helpstring'="unset procedure to debug",
'operator'=ts("unstopat"),
'submenu'=["hackware"],
NULL
):
Install(newCM):
f := proc(x::integer)::integer;
option foobar;
global a;
local y::integer;
y:=(x-1)*17;
y;
end proc:
f(3):=8/5:
# Now, right-click on this name below.
# The new submenus are titled "procedure" (appearing in the
# middle group) and "hackware" (appearing at bottom).
f;
acer
2 hours 24 min ago
2 hours 48 min ago
3 hours 33 min ago
4 hours 44 min ago
4 hours 44 min ago
5 hours 24 min ago
5 hours 38 min ago
6 hours 26 min ago
6 hours 45 min ago
6 hours 56 min ago