FoxInCloud
Adapting sfMenu (answer to Brandon Lee)
Gravatar is a globally recognized avatar based on your email address. Adapting sfMenu (answer to Brandon Lee)
  FoxInCloud Support - Thierry N.
  All
  Jan 15, 2024 @ 12:20pm

The menu I am referring to is not VFP menu but downloaded from here: https://github.com/VFPX/OOPMenu. There are a lot of logic be programmed such as the menu item will be enabled when user has the privilege. Now, how do I substitute such as menu? Change back to VFP menu?

You need to modify code in sfMenu.vcx to replace any menu command by a call to wMenu() (modify command awPublic.prg)

eg.

&& replace
define popup (.cPopupNameThis) margin relative shadow color scheme 4

&& by
wMenu(textmerge([define popup <<.cPopupNameThis>> margin relative shadow color scheme 4]))

Here is a sample menu program generated from a *.mnx by home(1) + "tools\ab\awMenuGen.prg"

Here is the full documentation:

To adapt any menu command or function to LAN (desktop) mode and Web mode, pass it as a character string to wMenu(); (FoxInCloud Adaptation Assistant adapts all your menu instructions that way)

DEFI POPU myPopup MARGIN	RELA SHADOW COLOR W+/B* && command before adaptation
wMenu('DEFI POPU myPopup MARGIN	RELA SHADOW COLOR W+/B* ') && command after adaptation
&& note: wMenu() expands standard abbreviated Visual FoxPro keywords and parses any number of spaces or tabs around clauses

Except ON SELECTION commands and SKIP FOR expressions, expressions inside clauses must be expressed as literals; To convert expressions to literals, simply place your instruction in Textmerge() and enclose expressions within "<<>>"

lcPrompt = "Display contents of myFile"
DEFINE BAR 2 OF myPopup PROMPT m.lcPrompt SKIP FOR !FILE("myFile.ext") && command before adaptation
wMenu(Textmerge('DEFINE BAR 2 OF myPopup PROMPT "<<m.lcPrompt>>" SKIP FOR !FILE("myFile.ext")')) && command after adaptation

To make it even more simple, you can use the FoxInCloud cLitteral() function (aliased as cL); cLitteral() [alias cL()] supports expressions of any type:

liBar = 2
lcPrompt = "Display contents of myFile"
DEFINE BAR m.liBar OF myPopup PROMPT m.lcPrompt SKIP FOR !FILE("myFile.ext") && command before adaptation
wMenu(Textmerge('DEFINE BAR <<cL(m.liBar)>> OF myPopup PROMPT <<cL(m.lcPrompt)>> SKIP FOR !FILE("myFile.ext")')) && command after adaptation

To control whether menu command execution is OK, you can chain your wMenu() command calls with .AND.; If any error occurs, execution chain will stop on the offending instruction, and the second parameter passed by reference will hold the error message:

local success, result
success = .T.;
	and wMenu('DEFI POPU myPopup MARGIN RELATIVE SHADOW COLOR W+/B*', @m.result);
	and wMenu('ON SELECTION BAR 2 OF myPopup loMyForm.myMethod(m.myValue)', @m.result)
assert m.success message m.result
if m.success
	...
endif

Just before executing ACTIVATE commands such as:

wMenu('ACTIVATE MENU|POPUP ...', @m.result)
wMenu('ON PAD|BAR ... ACTIVATE MENU|POPUP xxx', @m.result)

for a MENU or POPUP having SKIP FOR and/or ON SELECTION clauses relying on variables, e.g.

wMenu('ON SELECTION BAR 2 OF myPopup loMyForm.myMethod(m.myValue)', @m.result);
wMenu('DEFINE PAD|BAR ... SKIP FOR myFunction(m.myValue)', @m.result)

(keywords such as this and thisform can't be used in ON SELECTION and SKIP FOR clauses as they execute outside of the form's context)

... Make sure to pass by reference an object as second parameter [@m.result], with properties holding any variable required for SKIP FOR and ON SELECTION clauses

local success, result
success = .T.;
	and wMenu('DEFI POPU myPopup MARGIN RELATIVE SHADOW COLOR W+/B*', @m.result);
	and wMenu('DEFINE BAR 2 OF myPopup PROMPT "xx" SKIP FOR m.myBoolean', @m.result);
	and wMenu('ON SELECTION BAR 2 OF myPopup loMyForm.myMethod(m.myValue)', @m.result);
	;
	and varSet(@m.result, CreateObject('Empty')); && you create an object which defines the parameters that are required for your ON SELECTION commands and SKIP FOR expressions
	and AddProperty(m.result, 'loMyForm', thisForm);
	and AddProperty(m.result, 'myValue', m.myValue);
	and AddProperty(m.result, 'myBoolean', m.myBoolean);
	and wMenu('ACTIVATE POPUP myPopup ... NOWAIT', @m.result) && m.result contains: - on call, the 'parameter object' - on return, error message if any, else .null.
assert m.success message m.result

Please note that, for parameters of type Object, ONLY references to form or form members are supported. e.g. if you need a reference to an object, make sure that this object is added to any container within the form, or the form itself:

local loMyObject, success, result
thisForm.AddObject('oObject', 'myCustom', InitParm)
loMyObject = thisForm.oObject
success = .T.;
	and wMenu('DEFI POPU myPopup MARGIN RELATIVE SHADOW COLOR W+/B*', @m.result);
	and wMenu('ON SELECTION BAR 2 OF myPopup loMyObject.myMethod(m.myValue)', @m.result);
	and varSet(@m.result, CreateObject('Empty')); && you create an object which defines the parameters that are required for your ON SELECTION commands and SKIP FOR expressions
	and AddProperty(m.result, 'loMyObject', m.loMyObject); && loMyObject is needed to evaluate some SKIP FOR expression or execute some ON SELECTION command
	and AddProperty(m.result, 'myValue', m.myValue);
	and wMenu('ACTIVATE POPUP myPopup ... NOWAIT', @m.result)
assert m.success message m.result

if you:

  • use the ACTIVATE MENU|POPUP without the NOWAIT clause,
  • expect some code to execute after MENU|POPUP gets DEACTIVATEd,

Make sure to:

  • move the code located after the ACTIVATE MENU|POPUP command to another method (AKA call-back method) - this code move is similar to what you already do for code processing the response of a modal form
  • add 2 properties to the above-mentioned parameter object: . woCallBack: reference to the form member holding the call-back method, = this typically . wcCallBack: name of the call-back method, = 'wFormCallBack*' typically

Important:

  • if either .woCallBack or .wcCallBack is not passed or do not match a valid object and public method, the code you currently have after ACTIVATE MENU|POPUP WILL NOT EXECUTE in Web mode.
  • the call-back object (.woCallBack) MUST BE a form or a form member.
  • make sure not to use woCallBack or wcCallBack as variable names as defined above.
local loMyObject, success, result
thisForm.AddObject('oObject', 'myCustom', InitParm)
loMyObject = thisForm.oObject
success = .T.;
	and wMenu('DEFI POPU myPopup MARGIN RELATIVE SHADOW COLOR W+/B*', @m.result);
	and wMenu('ON SELECTION BAR 2 OF myPopup loMyObject.myMethod(m.myValue)', @m.result);
	and varSet(@m.result, CreateObject('Empty')); && you create an object which defines the parameters that are required for your ON SELECTION commands and SKIP FOR expressions
	and AddProperty(m.result, 'loMyObject', m.loMyObject); && loMyObject is needed to evaluate some SKIP FOR expression or execute some ON SELECTION command
	and AddProperty(m.result, 'myValue', m.myValue);
	and AddProperty(m.result, 'woCallBack', m.this);
	and AddProperty(m.result, 'wcCallBack', 'wFormCallBack'); && this.wFormCallBack() will execute when myPopup deactivates
	and wMenu('ACTIVATE POPUP myPopup ...', @m.result)
assert m.success message m.result

wMenu() also executes menu functions:

&& function call before adaptation:
? Prmba( "myPopup", 2 )
&& function call after adaptation:
? wMenu('Prmba( "myPopup", 2 )', @m.result)

If an error occurs, wMenu('menuFunction()', @m.result) returns .null. (In logical tests such as IF, Iif(), case, etc., VFP coerces .null. to .F.)

local lcPrmBar, success
lcPrmBar = wMenu('Prmba( "myPopup", 2 )', @m.result)
success = not IsNull(m.lcPrmBar)
assert m.success message m.result
if m.success
	do something with m.lcPrmBar
endif
© 1996-2024