Toolbar menu scroll bar

In a future update, is it possible to add a side scroll bar to the toolbar menu, for those instances when the menu contains so many items it runs off the bottom of my computer screen?
I’m currently working on a monster 4-game combination module, which contains over 50 off-map displays of one kind or another. Right now, there’s no way I can figure out how players can access the very bottom items.

Doesn’t the toolbar wrap? Perhaps a screenshot of the problem would help us see what you’re seeing.

I fear it depends on the Look’n’Feel (LnF). I believe the GTK LnF is OK, but the default Metal may not be. I seem to remember people complaining about a similar issue with the drop-down .vsav selection tine start-up wizard.

Technically, I don’t think the problem is whether the toolbar “wraps” - but rather that very long menus extend beyond the bottom of the screen - which is really a different problem than the toolbar.

@fumanpo perhaps you can give some details on your set-up (see How to report problems). Also, you can try to set a different LnF by looking at How to set the VASSAL Look’n’Feel and see if any of that helps.

Yours,
Christian

Here is a screenshot:

There are items beyond the bottom edge of my monitor I can’t access. And I have a fairly generous 38-inch monitor, so it’ll be worse for many folks with more conventional monitor sizes.
I’ll have to play the Look-n-Feel settings when I have more time, to see if that improves anything.

Ok, that’s not the toolbar itself, but a menu which drops down from a button on the toolbar. I’m sure the LaF settings won’t affect this at all.

I tested it.

import java.awt.*;
import java.awt.event.*;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Menu
{
    public JMenuBar createMenuBar() {
        //Create the menu bar.
        JMenuBar menuBar = new JMenuBar();

        //Build the first menu.
        JMenu menu = new JMenu("A Menu");
        menu.setMnemonic(KeyEvent.VK_A);
        menu.getAccessibleContext().setAccessibleDescription(
                "The only menu in this program that has menu items");
        menuBar.add(menu);

        //a group of JMenuItems
        for (int i = 1; i <= 100; i++) {
            JMenuItem menuItem = new JMenuItem("Entry # "+i);
            menu.add(menuItem);
        }

        return menuBar;
    }

    public Container createContentPane() {
        JPanel contentPane = new JPanel(new BorderLayout());

        //Create a scrolled text area.
        JTextArea output = new JTextArea(5, 30);
        JScrollPane scrollPane = new JScrollPane(output);
        
        output.setEditable(false);
        
        contentPane.setOpaque(true);
        contentPane.add(scrollPane, BorderLayout.CENTER);

        return contentPane;
    }
        
    private static void initLookAndFeel(String laf) {
        String       lafClass = null;
        final String cross    = UIManager.getCrossPlatformLookAndFeelClassName();
        final String system   = UIManager.getSystemLookAndFeelClassName();

        System.out.println("Available L'n'Fs:");
        for (UIManager.LookAndFeelInfo info :
                 UIManager.getInstalledLookAndFeels()) {
            System.out.println(String.format("  %-20s: %s",
                                             info.getName(),
                                             info.getClassName()));
        }
        System.out.println(String.format("  %-20s: %s","System",system));
        System.out.println(String.format("  %-20s: %s","Cross", cross));
            
        if (laf != null) {
            if (laf.equals("Cross"))
                lafClass = cross;
            else if (laf.equals("System"))
                lafClass = system;
            for (UIManager.LookAndFeelInfo info :
                     UIManager.getInstalledLookAndFeels()) {
                if (laf.equals(info.getName())) {
                    lafClass = info.getClassName();
                }
            }
        }
            
        if (lafClass == null) {
            System.err.println("Unexpected value of Look'n'Feel specified: "
                               + laf);
        }
        else {
            try {
                UIManager.setLookAndFeel(lafClass);
            }
            catch (ClassNotFoundException e) {
                System.err.println("Couldn't find class for specified L'n'F:"
                                   + laf);
                System.err.println("Using the default L'n'F.");
            } 
            catch (UnsupportedLookAndFeelException e) {
                System.err.println("Can't use the specified L'n'F ("+ laf
                                   + ") on this platform.");
                System.err.println("Using the default L'n'F.");
            } 
            catch (Exception e) {
                System.err.println("Couldn't get specified L'n'F ("+ laf
                                   + "), for some reason.");
                System.err.println("Using the default L'n'F.");
                e.printStackTrace();
            }
        }
        System.out.println("Using L'n'F: "+UIManager.getLookAndFeel().getName());
    }
    
    private static void createAndShowGUI(String laf) {
        initLookAndFeel(laf);
        
        //Create and set up the window.
        JFrame frame = new JFrame("MenuLookDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        Menu demo = new Menu();
        frame.setJMenuBar(demo.createMenuBar());
        frame.setContentPane(demo.createContentPane());

        //Display the window.
        frame.setSize(450, 260);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI(args.length > 0 ? args[0] : null);
            }
        });
    }
}

Save the above to Menu.java and do

$ javac Menu.java
$ java Menu
$ java Menu <LnF>

were <LnF> is one of the available LnFs.

The code creates a ridiculously long menu. In all cases, the menu extends beyond the bottom of the screen.

Actually, since Java delegates a lot to the L’n’F, it could be possible that the underlying L’n’F could add scroll capability to the menus.

An option would be to use something like MenuScroller.

Yours,
Christian

Along the same line of thought: is it also possible to add the user option of inserting thin dividing lines to organize modules with very high numbers of off-map boxes in the drop-down menu? Ideally it would be identical to the existing Menu Separator trait that can be inserted into the right-click menus for individual pieces. Thx

Is there a reason you can’t divide these displays across buttons?

That thought did just occur to me a short while ago.
Reorganizing everything into 4-5 separate pull-down menus would easily accomplish the same goal.

Or, you could define sub-menus as you already have it for Soviet Reinforcements and Axis Reinforcements. E.g.,

  • The Hero City
    • Soviet
      • Off-board boxes
      • Dead-pile
      • Breakdown regiments
      • Formations
      • Reinforcements
      • RVGK
    • Axis
  • The Forgotton Battles

Of course, if the groups The Hero City, The Forgotton Battles, The Third Winter, and Crimea corresponds to orthogonal choices - which they seem to be in Ostfront, then the non-active menus could be turned off by an appropriate property.

Yours,
Christian