Application Center - Maplesoft

App Preview:

Build your own context-sensitive menu

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

contextmenu.mws

Context-Sensitive Menu for Calculus 1 problems

by Karen Ranger

This application shows how easy it is to build your own non-standard context-sensitive menu.  A context-sensitive menu associates expressions with specific Maple actions.  Once an action is selected, not only is the action performed on the expression, but the Maple routine is also displayed to show users the corresponding Maple command.  The context-sensitive menu presented in this application provides an interface to several of the routines in the Student[Calculus1] package.  Specifically, users will be able to walk through differentiation problems by applying rules, asking for a hint or undoing the previous rule applied.  

Definitions

To build a context-sensitive menu, you first need to define a class, called CF_CLASS, which will contain a unique name for the menu, called the Key, a Boolean statement that will test expressions for membership in this class, and an explanation of what the class contains.  

Once the class has been defined, you need to define actions.  These action, called CF_ACTION, will have the following entries:

MenuString       The string that appears in the context-sensitive menu.             
HelpString         The text that appears in the bubble help.                          
CodeType         The type of action, such as "complete" or a CF_CODETYPE structure.
Code                The Maple code that should be used to process the object.    

Simple example

>    with(context);

[buildcontext, clearlabels, defaultcontext, display, installcontext, restoredefault, testactions, troubleshoot]

>    SimpleMenu:=
   CF_CLASS(
        "Key" = "Hint",
        "Test" = "type(f, specfunc(anything,Diff))
or evalb(Student:-Calculus1:-Hint(f)<>[NULL])",
        "Description" = "Ask for a hint to the problem",
 
        CF_ACTION(
            "MenuString" = "Hint",
            "HelpString" = "Ask for a hint",
            "CodeType" = "complete",
            "Code" = "Student:-Calculus1:-Hint(f)"
        )):

Since the output of buildcontext  is quite long, end this expression with a colon to suppress the output.

>    CM := buildcontext(SimpleMenu):

Install the context-sensitive menu.

>    installcontext(CM):

Let's try our simple menu.

>    Diff(sin(x)*x, x);

Diff(sin(x)*x,x)

>    R0 := Student:-Calculus1:-Hint(Diff(sin(x)*x,x));

R0 := [product]

Another example

>    Int(cos(x), x);

Int(cos(x),x)

Right click on the output and select Hint from the menu.

>    R1 := Student:-Calculus1:-Hint(Int(cos(x),x));;

R1 := [cos]

When right clicking on the following expression, notice that the Hint command does not appear.  This is because the expression sin(x) fails to pass the Boolean test.

>    sin(x);

sin(x)

Procedures to reduce the amount of code displayed to users

The following procedures have been created to reduce the amount of code seen by novice users.  Now when an option from the context-sensitve menu is selected, users will see

ApplyProductRule(Diff(sin(x)*x,x);

as the Maple input as opposed to


if nops([Student:-Calculus1:-Rule[product](f), Student:-Calculus1:-GetMessage()])=1 then  
      Student:-Calculus1:-Rule[product](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

>    restart;

>    ApplyProductRule :=  (f) ->
   if nops([Student:-Calculus1:-Rule[product](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[product](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyChainRule := (f) -> if nops([Student:-Calculus1:-Rule[chain](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[chain](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyConstantRule := (f) -> if nops([Student:-Calculus1:-Rule[constant](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[constant](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyConstantMultipleRule := (f) -> if nops([Student:-Calculus1:-Rule[`c*`](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[`c*`](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyDifferenceRule := (f) -> if nops([Student:-Calculus1:-Rule[difference](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[difference](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyIdentityRule := (f) -> if nops([Student:-Calculus1:-Rule[identity](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[identity](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyPowerRule := (f) -> if nops([Student:-Calculus1:-Rule[power](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[power](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyProductRule := (f) -> if nops([Student:-Calculus1:-Rule[product](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[product](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyQuotientRule := (f) -> if nops([Student:-Calculus1:-Rule[quotient](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[quotient](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplySumRule := (f) -> if nops([Student:-Calculus1:-Rule[sum](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[sum](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplySinRule := (f) -> if nops([Student:-Calculus1:-Rule[sin](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[sin](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyCosRule := (f) -> if nops([Student:-Calculus1:-Rule[cos](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[cos](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

ApplyTanRule := (f) -> if nops([Student:-Calculus1:-Rule[tan](f), Student:-Calculus1:-GetMessage()])=1
   then
Student:-Calculus1:-Rule[tan](f);
   else
      op(1, [Student:-Calculus1:-GetMessage()])
   end if:

>   

Code for the Calculus 1 menu

The routines to build your own context-sensititve menu are located in the context  package

>    with(context);

[buildcontext, clearlabels, defaultcontext, display, installcontext, restoredefault, testactions, troubleshoot]

The context-sensitive menu that we are defining here is called CMCalc.   In the following example, the unique name for CF_CLASS  is "Differentiate".  The Boolean statement tests if an expression is in the inert differentiation form.  This is required to access the routines from within the Student[Calculus1] package.  A second test is performed to verify if a hint can be applied to the problem.  This is needed to invoke the context-sensitive menu on expressions that are incomplete while in the single-stepping process.  The description for this menu is, "Step through differentiation problems".

>    CMCalc:=
   CF_CLASS(
        "Key" = "Differentiate",
        "Test" = "type(f, specfunc(anything,Diff))
or evalb(Student:-Calculus1:-Hint(f)<>[NULL])",
        "Description" = "Step through differentiation problems",
 
        CF_ACTION(
            "MenuString" = "Hint",
            "HelpString" = "Ask for a hint",
            "CodeType" = "complete",
            "Code" = "Student:-Calculus1:-Hint(f)"
        ),

        CF_ACTION(
            "MenuString" = "Undo",
            "HelpString" = "Undo the rule applies",
            "CodeType" = "complete",
            "Code" = "Student:-Calculus1:-Undo(f)"
        ),

        CF_ACTION(
            "MenuString" = "Chain Rule",
            "HelpString" = "Apply the Chain Rule",
            "CodeType" = "complete",
            "Code" = "ApplyChainRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Constant Rule",
            "HelpString" = "Apply the Constant Rule",
            "CodeType" = "complete",
            "Code" = "ApplyConstantRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Constantmultiple Rule",
            "HelpString" = "Apply the Constant Multiple Rule",
            "CodeType" = "complete",
            "Code" = "ApplyConstantMultipleRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Difference Rule",
            "HelpString" = "Apply the Difference Rule",
            "CodeType" = "complete",
            "Code" = "ApplyDifferenceRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Identity Rule",
            "HelpString" = "Apply the Identity Rule",
            "CodeType" = "complete",
            "Code" = "ApplyIdentityRule(f)"
        ),


        CF_ACTION(
            "MenuString" = "Power Rule",
            "HelpString" = "Apply the Power Rule",
            "CodeType" = "complete",
            "Code" = "ApplyPowerRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Product Rule",
            "HelpString" = "Apply the Product Rule",
            "CodeType" = "complete",
            "Code" = "ApplyProductRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Quotient Rule",
            "HelpString" = "Apply the Quotient Rule",
            "CodeType" = "complete",
            "Code" = "ApplyQuotientRule(f)"
        ),

        CF_ACTION(
            "MenuString" = "Sum Rule",
            "HelpString" = "Apply the Sum Rule",
            "CodeType" = "complete",
            "Code" = "ApplySumRule(f)"
        ),
       
       CF_ACTION(
            "MenuString" = "Sin Rule",
            "HelpString" = "Apply the Sin Rule",
            "CodeType" = "complete",
            "Code" = "ApplySinRule(f)"
       ),

       CF_ACTION(
            "MenuString" = "Cos Rule",
            "HelpString" = "Apply the Cos Rule",
            "CodeType" = "complete",
            "Code" = "ApplyCosRule(f)"
        ),

       CF_ACTION(
            "MenuString" = "Tan Rule",
            "HelpString" = "Apply the Tan Rule",
            "CodeType" = "complete",
            "Code" = "ApplyTanRule(f)"
        )

):

>    display(CMCalc);

- Hint

- Undo

- Chain Rule

- Constant Rule

- Constantmultiple Rule

- Difference Rule

- Identity Rule

- Power Rule

- Product Rule

- Quotient Rule

- Sum Rule

- Sin Rule

- Cos Rule

- Tan Rule

Since the output of buildcontext  is quite long, end this expression with a colon to suppress the output.

>    CM := buildcontext(CMCalc):

Install the context-sensitive menu.

>    installcontext(CM):

Test Your Example

Now let's ensure that each possible action provides the expected results. The testactions  function is used to return a table that indicates the actual command generated for each action. In particular, the command testactions[defaultcontext](e)  tests against the original system default context menu.

Note: The interactive  command is the last routine tested in when invoking testactions  therefore the interactive maplet should appear.

>    testactions[defaultcontext](Diff(sin(x)*x, x));

### Menu -> "System_Math Functions"

    "x" = ["R0 := diff(Diff(sin(x)*x,x),x);"]

    "x" = ["R1 := int(Diff(sin(x)*x,x),x);"]

    "Evaluate" = ["R2 := value(Diff(sin(x)*x,x));"]

    "Real Part" = ["R3 := Re(Diff(sin(x)*x,x));"]

    "Imaginary Part" = ["R4 := Im(Diff(sin(x)*x,x));"]

    "Absolute Value" = ["R5 := abs(Diff(sin(x)*x,x));"]

    "Argument" = ["R6 := argument(Diff(sin(x)*x,x));"]

    "Conjugate" = ["R7 := conjugate(Diff(sin(x)*x,x));"]

    "Truncate" = ["R8 := trunc(Diff(sin(x)*x,x));"]

    "Round" = ["R9 := round(Diff(sin(x)*x,x));"]

    "Fractional Part" = ["R10 := frac(Diff(sin(x)*x,x));"]

    "Floor" = ["R11 := floor(Diff(sin(x)*x,x));"]

    "Ceiling" = ["R12 := ceil(Diff(sin(x)*x,x));"]

    "Assuming Real" = ["R13 := simplify(Diff(sin(x)*x,x),'assume = real');"]

    "Assuming Positive" = ["R14 := simplify(Diff(sin(x)*x,x),'assume = positive');"]

    "Assuming Non-negative" = ["R15 := simplify(Diff(sin(x)*x,x),'assume = nonnegative');"]

    "Size" = ["R16 := simplify(Diff(sin(x)*x,x),'size');"]

    "Symbolic" = ["R17 := simplify(Diff(sin(x)*x,x),'symbolic');"]

    "Maple" = ["R18 := sprintf(\"%a\",Diff(sin(x)*x,x));"]

    "LaTeX" = ["latex(Diff(sin(x)*x,x));"]

    "MathML" = ["R19 := MathML['Export'](Diff(sin(x)*x,x));"]

    "C Language" = ["R20 := CodeGeneration['C'](Diff(sin(x)*x,x),'optimize');"]

    "Fortran" = ["R21 := CodeGeneration['Fortran'](Diff(sin(x)*x,x),'optimize');"]

    "Java" = ["R22 := CodeGeneration['Java'](Diff(sin(x)*x,x),'optimize');"]

Initializing Java runtime environment.

    "Plot Builder" = [[`ERROR: `, "insufficient parameters for algebraic format"]]

### Menu <-

Now let's test our menu

>    testactions(Diff(sin(x)*x, x)):

### Menu -> "Differentiate"

    "Hint" = ["R23 := Student:-Calculus1:-Hint(Diff(sin(x)*x,x));"]

    "Undo" = ["R24 := Student:-Calculus1:-Undo(Diff(sin(x)*x,x));"]

    "Chain Rule" = ["R25 := ApplyChainRule(Diff(sin(x)*x,x));"]

    "Constant Rule" = ["R26 := ApplyConstantRule(Diff(sin(x)*x,x));"]

    "Constantmultiple Rule" = ["R27 := ApplyConstantMultipleRule(Diff(sin(x)*x,x));"]

    "Difference Rule" = ["R28 := ApplyDifferenceRule(Diff(sin(x)*x,x));"]

    "Identity Rule" = ["R29 := ApplyIdentityRule(Diff(sin(x)*x,x));"]

    "Power Rule" = ["R30 := ApplyPowerRule(Diff(sin(x)*x,x));"]

    "Product Rule" = ["R31 := ApplyProductRule(Diff(sin(x)*x,x));"]

    "Quotient Rule" = ["R32 := ApplyQuotientRule(Diff(sin(x)*x,x));"]

    "Sum Rule" = ["R33 := ApplySumRule(Diff(sin(x)*x,x));"]

    "Sin Rule" = ["R34 := ApplySinRule(Diff(sin(x)*x,x));"]

    "Cos Rule" = ["R35 := ApplyCosRule(Diff(sin(x)*x,x));"]

    "Tan Rule" = ["R36 := ApplyTanRule(Diff(sin(x)*x,x));"]

### Menu <-

Let's try it out.  Right click on the output and select from the menu.  Do this until you have walked through each stage of this problem.

>    Diff(sin(x)*cos(x), x);

Diff(sin(x)*cos(x),x)

>    R38 := ApplyProductRule(Diff(sin(x)*cos(x),x));

R38 := Diff(sin(x)*cos(x),x) = Diff(sin(x),x)*cos(x)+sin(x)*Diff(cos(x),x)

>    R39 := ApplyCosRule(Diff(sin(x)*cos(x),x) = Diff(sin(x),x)*cos(x)+sin(x)*Diff(cos(x),x));

R39 := Diff(sin(x),x)*cos(x)+sin(x)*Diff(cos(x),x) = Diff(sin(x),x)*cos(x)-sin(x)^2

>    R40 := ApplySinRule(Diff(sin(x),x)*cos(x)+sin(x)*Diff(cos(x),x) = Diff(sin(x),x)*cos(x)-sin(x)^2);

R40 := Diff(sin(x),x)*cos(x)-sin(x)^2 = cos(x)^2-sin(x)^2

>    R37 := Student:-Calculus1:-Hint(Diff(sin(x)*cos(x),x));

R37 := [product]

>   

Restore Default

CM will remain as the context menu system until the end of the session, or until installcontext  is called with a new recognizer, or until the default configuration is recalled through the restoredefault . The syntax is simply:

>    restoredefault();

ContextMenu

>   

The Maple restoredefault  function is similar to restart  in a worksheet.

The Default Configuration File

The default context-generating procedure is constructed from the configuration as illustrated on Maple's context worksheet . This configuration can be edited and reinstalled in the manner described previously.

For more information or to see the advanced options available in the context  package, visit Maple's Help page by entering ?context  at the Maple prompt.