Using "Load" to bring up a sub menu

Please check the FAQ (https://www.xyplorer.com/faq.php) before posting a question...
klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Using "Load" to bring up a sub menu

Post by klownboy »

Hi, I've be struggling trying to fix a syntax problem in a script I'm writing. I'm hoping someone might be able to help me out or point me in the right direction. It's been driving me nuts all day. The menu uses a couple of developed variables and also uses heredoc. I have a sub menu I want to show up only after clicking on the item in the main menu, but instead it rears its ugly head on the main menu. If I use the exact same variable ($toolmen) and write to a script file the menu looks and works just fine, but I can't get it to display properly when using SC load with the "s" parameter like so, "load ($toolmen, , "s");" The code lines under the "Save menu item don't show up or execute until the Save heading is clicked, but the load of $toolmen does. Here the portion of the script.

Code: Select all

   if ($toolbars) {
     $toolmen = "";
     foreach ($item, $toolbars, "|") {
       $toolmen = $toolmen . "      $item"<crlf>;
       $toolmen = $toolmen . "  toolbar(readfile(""$DIR_TOOLBARS\$item.txt""));<crlf>";
     }
	$toolmen = """Vertical Toolbars|$ICO_TOOLBARS""" . ";" . <crlf> . $toolmen;
   }
   //writefile("<xyscripts>\ToolM.xys", $toolmen, o);  if I use this line and later use the "f" parameter with load it works fine
   
   $savemenu = <<<#SAV
"Save Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
   $TB_name = input("Save current toolbar as:  ", "Change this text here" , , "s");
   writefile("$DIR_TOOLBARS\$TB_name.txt", $TB_build);
"Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load ("$toolmen", ,"s");
#SAV;

  $ctbScript = $ctbScript . "-" . <crlf> . $savemenu;
	Load ($ctbScript, , "s");
The menu is displaying as seen here, but what I want to happen is the Vertical Toolbar menu to display only when that main menu item is clicked.
vToolBar_capture.PNG
vToolBar_capture.PNG (12.67 KiB) Viewed 2801 times
As I said above, if I write "$toolmen" to a xys script "file", and then below the Vertical Toolbar title, I use load with the "f" parameter, it looks and works as it should (i.e., the menu comes up separately) as a sparate sub-menu. I originally had the $toolmen developed directly under the menu item with in the herdoc and that was even worse due to the <crlf> problems even using chr(13) didn't help. Any thoughts on what I may do doing wrong? Thanks,
Ken
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

TheQwerty
Posts: 4373
Joined: 03 Aug 2007 22:30

Re: Using "Load" to bring up a sub menu

Post by TheQwerty »

Look at what the parsed and resolved output is (right click the bottom pane of the stepping dialog) right before it calls the final load SC:
load
----
$ctbScript-
"Save Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
$TB_name = input("Save current toolbar as: ", "Change this text here" , , "s");
writefile("$DIR_TOOLBARS\$TB_name.txt", $TB_build);
"Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
load (""Vertical Toolbars|$ICO_TOOLBARS";
" $toolbars"
toolbar(readfile("$DIR_TOOLBARS\$toolbars.txt"));
", ,"s");

----

----
s
So the script you're passing leads to the 'Vertical Toolbars' script being broken and the rest of the script you mean to only use there shows up in the main script.

You must go deeper! Nesting the script within another heredoc should work as you desire:

Code: Select all

  if ($toolbars) {
    $toolmen = "";
    foreach ($item, $toolbars, "|") {
      $toolmen = $toolmen . "      $item"<crlf>;
      $toolmen = $toolmen . "  toolbar(readfile(""$DIR_TOOLBARS\$item.txt""));<crlf>";
    }
    $toolmen = """Vertical Toolbars|$ICO_TOOLBARS""" . ";" . <crlf> . $toolmen;
  }

  $savemenu = <<<#SAV
"Save Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
  $TB_name = input("Save current toolbar as:  ", "Change this text here" , , "s");
  writefile("$DIR_TOOLBARS\$TB_name.txt", $TB_build);
"Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
  load (<<<VERTICALTOOLBARSCRIPT
$toolmen
VERTICALTOOLBARSCRIPT
  , ,"s");
#SAV;

  $ctbScript = $ctbScript . "-" . <crlf> . $savemenu;
  Load ($ctbScript, , "s");

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

Hi TheQwerty, your fix using the nested heredoc under the menu worked. Originally the entire "if ($toolbars) {" section was under the menu heading, but I moved it out because the <crlf> were a big problem. So I was getting closer by moving it out from under the Vertical Toolbar section, but I should have used another heredoc within the load command. My parsed/resolved output did look like yours with ", ,"s"); at the end. I'm not sure why it ends up being broken and accounts for the $toolmen variable being displayed in the main menu. I'll remember to use the parsed and resolved output when issues arise. Was there anything I could have done to correct my original syntax and have it work?

Very much appreciated TheQwerty. It was indeed driving me crazy.
Thanks,
Ken
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

TheQwerty
Posts: 4373
Joined: 03 Aug 2007 22:30

Re: Using "Load" to bring up a sub menu

Post by TheQwerty »

klownboy wrote:I'm not sure why it ends up being broken and accounts for the $toolmen variable being displayed in the main menu.
It gets broken up because $toolmen contains line-breaks which means when this line (+heredoc):

Code: Select all

   $savemenu = <<<#SAV
"Save Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
   $TB_name = input("Save current toolbar as:  ", "Change this text here" , , "s");
   writefile("$DIR_TOOLBARS\$TB_name.txt", $TB_build);
"Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load ("$toolmen", ,"s");
#SAV;
gets executed it sets $savemenu to:

Code: Select all

"Save Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
   $TB_name = input("Save current toolbar as:  ", "Change this text here" , , "s");
   writefile("$DIR_TOOLBARS\$TB_name.txt", $TB_build);
"Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load (""Vertical Toolbars|$ICO_TOOLBARS";
"  $toolbars"
toolbar(readfile("$DIR_TOOLBARS\$toolbars.txt"));
", ,"s");
Which you should recognize as an invalid script - the Vertical Toolbars load starts with an empty string (not escaped) and doesn't really end, the " $toolbars" looks like a new script, and the toolbar(readfile...)); lacks indentation making it also look like a script.
klownboy wrote:Was there anything I could have done to correct my original syntax and have it work?
Not really... generating scripts within a script becomes complicated quite easily.

You could have made $toolbars a global or permanent variable, but then you'd have to either set $toolbars after you set $savemenu or do some work to escape $toolbars and prevent it from being resolved within the heredoc. That's a bit of a headache and difficult to manage though.

Another option would have been to just have the script generate separate script files for each menu level and have those be interconnected. Which is an okay approach but slightly sloppy.

I probably would have just constructed a single script with all the main menu items and sub-menu items, then use the labels parameter of load to modify how the menus are displayed. For example:

Code: Select all

"Script Builder"
  $subScripts = <<<SUBS
"Sub-Item 1 : _sub_1"
  Echo 'test';
"Sub-Item 2 : _sub_2"
  Echo 'test2';
SUBS;

  $mainScript = <<<MAIN
"Item 1 : item1"
  Echo 'item 1';
"Sub Menu... : submenu"
  Load '*', 'submenu;-;_sub_1;_sub_2', 's';
MAIN;

  $script = $mainScript . <crlf 2> . $subScripts;
  Load $script,, 's';
So the main menu actually contains all of the script but the sub-menu items are hidden. The item that shows the sub-menu uses load with the myself resource ('*') but specifies the exact labels to show in the menu. Granted, how I would go about building the $script variable would depend largely on how I'm creating the actual scripts they should contain.

What I really like about this last approach is the contents of $script is exactly what I would normally have in a script file. Thus I can debug the resulting script separately from the generating script by just putting it in a separate file. Moreover, if the creation of the script does not need to happen every time then I can have the generator write the script to a file and I now have a cached script that may reduce execution time, though I'd then need some cache-expiry and script-regeneration-triggering logic.


As I said script generation is just tricky business. ;)

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

Thanks TheQwerty for the explanations and the example script. I can follow the script no problem and I also stepped through it. The only thing as far as XY's handling of the script I'm a bit fuzzy on is, why does your very first line 'Script Builder" not appear? It's appears that XY is ignoring it (i.e., it's written like a heading for a menu, but it is not shown). I assume that because of the XY immediately reads the heredoc to obtain the values of the variable $subscripts and $mainscripts. To test I placed another heading, "Script Builder1" in the very beginning and then the 2 headings display and of course you have to click on the heading to have it execute the code below it. So it looks like you have to have at least two menu headings or the single one is basically ignored.

By the way, I actually did make $toolmen a perm variable and I tried to move locations around though probably not after the SAV heredoc as you mentioned. I could tell the last portion of the load $toolmanu was being broken because I could see it in the menu, but I thought there would be someway to correct it. Yes as you explained, there are a number of ways, but they involved using the heredoc to keep $toolmen in tact or using a different method entirely.

In writing this script I took the approach of writing the different sections like menu generation, menu loading and menu saving separately. Which I suppose is fine, but I should have thought more about the layout of the script as a whole first.

Thanks again,
Ken
Last edited by klownboy on 25 Feb 2015 13:56, edited 1 time in total.
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

bdeshi
Posts: 4249
Joined: 12 Mar 2014 17:27
Location: Asteroid B-612 / Dhaka
Contact:

Re: Using "Load" to bring up a sub menu

Post by bdeshi »

When there's only one subscript, it's executed automatically without displaying a menu.
After execing the script, the menus that pop up are generated by and reside within "Script Builder", but not siblings of it. The load command sort of has display access to subscripts in the same level only.

[ed]
Icon Names | Onyx | Undocumented Commands | xypcre
[ this user is asleep ]

PeterH
Posts: 2785
Joined: 21 Nov 2005 20:39
Location: Germany

Re: Using "Load" to bring up a sub menu

Post by PeterH »

Just a question: does it have advantages if you create a sub-script just to display a menu?
Wouldn't it be OK just to call popupmenu() :?:
Win11 Pro 223H2 Gerrman

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

PeterH wrote:...does it have advantages if you create a sub-script just to display a menu
Well I think it may in this case since the menu listing will be a selection of both XY built-in toolbar buttons and Customized User Buttons displayed vertically. So it wouldn't be so meaningfull to the end user if the menu didn't display the associated XY icons and user defined icons in it's display.
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

TheQwerty
Posts: 4373
Joined: 03 Aug 2007 22:30

Re: Using "Load" to bring up a sub menu

Post by TheQwerty »

To expound on Sammay's post...
klownboy wrote:why does your very first line 'Script Builder" not appear?
We have many layers of scripts.
  1. The initial script - this is the entire contents of that code block. It is a script named 'Script Builder' and the only* script in the resource so XY automatically executes it. When you added 'Script Builder1', you introduced a second script in the resource so XY gives you a choice between them. Running 'Script Builder' generates a new resource in the variable $script and then loads it without specifying any labels.
  2. XY runs the $script resource, which contains four scripts, but only two are visible ('Item 1' and 'Sub Menu...'). As we didn't specify any labels during the load XY presents a menu of just the two visible scripts. Then (assuming) the user selects 'Sub Menu...'.
  3. XY runs the 'Sub Menu...' script from the $script resource. This loads the current resource ($script) but with the specified labels ('submenu;-;_sub_1;_sub_2'). As we specified three labels, XY shows a menu containing these scripts (regardless of their visibility) - technically all four scripts in $script resource are still present, but the menu is only showing the ones we specified.
*Technically, this is about the number of visible scripts in the resource, not the total number of scripts in the resource. Though note there is a significant and confusing difference between hiding a script by underscoring its label vs underscoring its caption.

It gets confusing in part because we are lazy with our usage of the word "script" and refer to both the single script and the multi-script resource as just script. :eh:

PeterH wrote:Just a question: does it have advantages if you create a sub-script just to display a menu?
Wouldn't it be OK just to call popupmenu() :?:
You could certainly do it with popupmenu, it's just another approach.

The above has some advantages though...
  1. XY does the menu building and execution logic for you.
  2. You can use custom icons or menu item states (checked, disabled, default/bold).
  3. It was the only option before popupmenu was created so it can support older versions of XY.
  4. I find it easier than dealing with a 2D list of "Caption;Data" items.
Generally, I find popupmenu great as a replacement for simple InputSelects or when dealing with small things - like setting a variable to a single value. It seems to add unnecessary cruft when you're using it as a script menu. *shrugs*

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

Hi TheQwerty, thanks for the previous help and advice. I haven't made as much progress on the script as I would have liked. It's working other than the sub-menus. It's not from the lack of trying though this cold I have is not helping. The sub menu for the different vertical toolbars displays fine, but the actions provided below it are where I'm having issues. I'd like to to be able to harness the toolbar selected, the variable $item (which is perm up at he beginning of the script), would be set and then load the script using "load ('$self', '_vTB', 's')" This script label is part of the script resource file which I know is working since I use it with SC sub in the beginning of the script to get there. I also set a variable "$self" as the script resource file in case that was an issue since we are loading $ctbScript to accomplish this work. I'm getting the following error and I've tried countless different quoting arrangements/syntax. I'm not sure if it's because of a syntax/quoting issue or loading the script label issue, but like I said the labels are working fine within the script. Sorry for asking for help a once again, but any ideas on how to overcome this one?
'' is not a valid script command.
load ('D:\Tools\XYplorer\Scripts\vTB_working.xys', '_vTB', 's')
I think that particular message is because of my quoting on this run. Usually I receive a message such as the one below.

Code: Select all

   if ($toolbars) {
     $toolmen = "";
     foreach ($item, $toolbars, "|") {
       $toolmen = $toolmen . "      $item"<crlf>;
	   $toolmen = $toolmen . "  load ('$self', '_vTB', 's');<crlf>";
     }
	$toolmen = """Vertical Toolbars|$ICO_TOOLBARS""" . ";" . <crlf> . $toolmen;
   }

   $savemenu = <<<#SAV
"Generate a new Vertical Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load (<<<GENERATESCRIPT
'$self', '_TBselection', 's');
GENERATESCRIPT
"Load Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load (<<<VERTICALTOOLBARSCRIPT
$toolmen   
VERTICALTOOLBARSCRIPT
  , ,"s");
#SAV;


  $ctbScript = $ctbScript . "-" . <crlf> . $savemenu;
	Load ($ctbScript, , "s");
I'm having a similar issue with the other menu item for "Generating a new Vertical Toolbar."
The list of labels did not match any script in Script resource.
load
D:\Tools\XYplorer\Scripts\vTB_working.xys
_TBselection
s
For some reason loading the script label is not working there as well. When the user runs the script for the first time they will make selections and generate a new Vertical Toolbar. I like to send them back to the same code (via the script label when they want to generate another toolbar. I'm not sure if there's something special I need to do when calling a script resource label when loading from another loaded script "$ctbScript". Thanks,
Ken
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

TheQwerty
Posts: 4373
Joined: 03 Aug 2007 22:30

Re: Using "Load" to bring up a sub menu

Post by TheQwerty »

I only took a quick glance but try:

Code: Select all

   if ($toolbars) {
     $toolmen = "";
     foreach ($item, $toolbars, "|") {
       $toolmen = $toolmen . "      $item"<crlf>;
      $toolmen = $toolmen . "  load ('$self', '_vTB', 's');<crlf>";
     }
   $toolmen = """Vertical Toolbars|$ICO_TOOLBARS""" . ";" . <crlf> . $toolmen;
   }

   $savemenu = <<<#SAV
"Generate a new Vertical Toolbar|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load <<<GENERATESCRIPT
$self
GENERATESCRIPT
     , '_TBselection', 's';
    // I think you just misplaced the above line inside of GENERATESCRIPT instead of outside.
"Load Vertical Toolbars|D:\Graphics\Icons\Combined\Customize Toolbar on.ico";
     load (<<<VERTICALTOOLBARSCRIPT
$toolmen   
VERTICALTOOLBARSCRIPT
     , ,"s");
#SAV;


  $ctbScript = $ctbScript . "-" . <crlf> . $savemenu;
   Load ($ctbScript, , "s");
If that doesn't work then can you PM me a full script or archive of the script+whatever files it requires? (It's a little hard to debug when most of the variables are never set.)

You could also try making $savemenu the full script so that you can remove the heredocs in 'Generate a new Vert. Toolbar' and 'Load Vert. Toolbar' and instead use Load '*', $self_labels, 's' (and $toolmen_labels for the latter).

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

Thanks TheQwerty, I tried the change suggested and I received the same "The list of labels did not match any script in Script resource" error. I had the code that way during most of my runs so I was quite sure it would not work. I sent you the script. It doesn't require any support files.

Please note, it will NOT modify your toolbar or write to XY's ini file at any time. This is what I like about the idea, in that the toolbars are stored in a vToolbars folder off the XYdata folder and no changes are made to your toolbar. On the first run it will read the toolbar just to get a listing of your existing toolbar buttons but that's it. At that time your select the buttons you want and save the vToolbar to the vToolbar folder. Some of the code will look very familiar to you. :)
I'll continue tinkering with the script in the morning to see if the other suggestion works though I'm not entirely sure what you mean by having $savemenu include the entire script. Do you mean including $ctbScript as well?
Thanks,
Ken
Edit1: Please make sure the script copy I sent you has the initialization variable "$initTB" set to "0" on your first run so everything initializes properly. I think the copy I sent you did, but not positive.

Edit2: Sorry TheQwerty, I forgot to change the icon referred to in the two sub menus to an XY built-in before sending. I meant to change to ":conf" so that you wouldn't need any support files.
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

Hey TheQwerty, I can't believe it after so many attempts I was able to make the first submenu item work. I used the 'f' parameter which I had attempted 2 days ago but maybe not with the same quoting.

Code: Select all

"Generate a new Vertical Toolbar|:conf";
     load(<<<GENERATESCRIPT
$self
GENERATESCRIPT
  ,'_TBselection', 'f');
I also moved the sub "GLOBAL_BUTTONS : _GLOBAL_BUTTONS"; up as the very first label after "_Initialize". In addition,I moved the short establishment of $toolmen up right after the line "$toolbars = replace($toolbars, ".$EXT_TXT", "");" Neither of those 2 changes probably made any difference since I had tried them beforehand.

The inputselect box comes up to make the new selections and save the toolbar, but I have to work on the loading that menu which should come after the menu generation. It currently doesn't.

I had figured that maybe since we were loading $cbtScript the sub menus were not actually part of that script but the originating script so maybe the 'f' parameter might be necessary. Now to work on the other sub menu.
Thanks,
Ken

Edit: I also got the load menu to work by leaving the "s" as is where we load $toolmen, but used "f' parameter where we actually creat $toolmen i.e., $toolmen = $toolmen . " load('$self', '_vTB', 'f');<crlf>";), but I'm still having problem getting the proper menu to load. In that I need to somehow save that menu $item so it's properly recognized when I load the script label "_vTB". So getting closer anyway.
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

klownboy
Posts: 4146
Joined: 28 Feb 2012 19:27

Re: Using "Load" to bring up a sub menu

Post by klownboy »

Hi TheQwerty, finally everything is working. Thanks so much for your help. This was a bit of a nightmare. By the way, the final working lines in the $toolmen submenu look like this.

Code: Select all

	   $toolmen = $toolmen . "  perm $TBitem = $item;<crlf>";
	   $toolmen = $toolmen . "  load('$self', '_vTB', 'f');<crlf>";
In the body of the script, I use SC isSet to check if the perm variable was set. If not it uses the last accessed toolbar - which would be the typical situation. Of course the $TBitem variable has to be unset as soon as the toolbar menu is read.

My biggest obstacle now is the fact that there is no distinction in clicking a menu item with a left or right click of the mouse as there is with an actual CTB (get trigger). That capability would be a nice addition to XY's scripting features. Almost a necessity for scripts like this, but would also be valuable in other scripts as well. Yes, I know I could break up the menu items and use SC button '1' or '2', but honestly, that would be a mess.

By the way I discovered the other good reason for using a one item script caption in the script resource which is really 'doing' nothing but...avoids the error, script resource contains no visible scripts.

Thanks again TheQwerty, I really appreciate the help.
Ken
Windows 11, 23H2 Build 22631.3447 at 100% 2560x1440

CookieMonster

Re: Using "Load" to bring up a sub menu

Post by CookieMonster »

Klownboy - Can this script do identical right click on white space with menu names and sub-menus ? I want to place all the tool bar items within a right click on white with sub-menus.

Post Reply