From 2f5219615d5df3e8839e7c044b7d496d3b76efeb Mon Sep 17 00:00:00 2001 From: drdev Date: Thu, 3 Oct 2013 08:26:11 +0000 Subject: [PATCH] Create Forge button which, when clicked, displays popup menu containing items from old menu bar Support hiding status bar (F12) and saving title bar and status bar visibility between sessions Changed F1 to be a shortcut for launching the Forge wiki --- .gitattributes | 7 +- src/main/java/forge/control/FControl.java | 64 ++--- src/main/java/forge/gui/SOverlayUtils.java | 4 +- .../forge/gui/deckeditor/CDeckEditorUI.java | 4 +- .../forge/gui/framework/SResizingUtil.java | 16 +- src/main/java/forge/gui/home/CHomeUI.java | 8 +- .../home/sanctioned/CSubmenuConstructed.java | 6 +- .../home/sanctioned/ConstructedGameMenu.java | 2 +- src/main/java/forge/gui/match/CMatchUI.java | 4 +- .../gui/match/menus/CardOverlaysMenu.java | 2 +- .../forge/gui/match/menus/DevModeMenu.java | 6 +- .../java/forge/gui/match/menus/GameMenu.java | 2 +- src/main/java/forge/gui/menubar/FMenuBar.java | 120 --------- src/main/java/forge/gui/menus/ForgeMenu.java | 136 ++++++++-- src/main/java/forge/gui/menus/HelpMenu.java | 13 +- .../gui/{menubar => menus}/IMenuProvider.java | 2 +- src/main/java/forge/gui/menus/LayoutMenu.java | 34 ++- .../gui/{menubar => menus}/MenuUtil.java | 21 +- src/main/java/forge/gui/toolbox/FSkin.java | 2 +- .../forge/properties/ForgePreferences.java | 3 +- src/main/java/forge/view/FFrame.java | 24 +- src/main/java/forge/view/FNavigationBar.java | 86 ++++++ src/main/java/forge/view/FStatusBar.java | 4 +- src/main/java/forge/view/FTitleBar.java | 234 +--------------- src/main/java/forge/view/FTitleBarBase.java | 250 ++++++++++++++++++ src/main/java/forge/view/FView.java | 35 ++- 26 files changed, 613 insertions(+), 476 deletions(-) delete mode 100644 src/main/java/forge/gui/menubar/FMenuBar.java rename src/main/java/forge/gui/{menubar => menus}/IMenuProvider.java (92%) rename src/main/java/forge/gui/{menubar => menus}/MenuUtil.java (74%) create mode 100644 src/main/java/forge/view/FNavigationBar.java create mode 100644 src/main/java/forge/view/FTitleBarBase.java diff --git a/.gitattributes b/.gitattributes index 4e14ebe7d3c..01432ca7ab9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15260,12 +15260,11 @@ src/main/java/forge/gui/match/views/VPicture.java -text src/main/java/forge/gui/match/views/VPlayers.java -text src/main/java/forge/gui/match/views/VStack.java -text src/main/java/forge/gui/match/views/package-info.java svneol=native#text/plain -src/main/java/forge/gui/menubar/FMenuBar.java -text -src/main/java/forge/gui/menubar/IMenuProvider.java -text -src/main/java/forge/gui/menubar/MenuUtil.java -text src/main/java/forge/gui/menus/ForgeMenu.java -text src/main/java/forge/gui/menus/HelpMenu.java -text +src/main/java/forge/gui/menus/IMenuProvider.java -text src/main/java/forge/gui/menus/LayoutMenu.java -text +src/main/java/forge/gui/menus/MenuUtil.java -text src/main/java/forge/gui/package-info.java svneol=native#text/plain src/main/java/forge/gui/toolbox/CardFaceSymbols.java svneol=native#text/plain src/main/java/forge/gui/toolbox/FAbsolutePositioner.java -text @@ -15489,8 +15488,10 @@ src/main/java/forge/util/storage/StorageReaderFolder.java -text src/main/java/forge/util/storage/package-info.java -text src/main/java/forge/view/ButtonUtil.java svneol=native#text/plain src/main/java/forge/view/FFrame.java -text +src/main/java/forge/view/FNavigationBar.java -text src/main/java/forge/view/FStatusBar.java -text src/main/java/forge/view/FTitleBar.java -text +src/main/java/forge/view/FTitleBarBase.java -text src/main/java/forge/view/FView.java -text src/main/java/forge/view/Main.java -text src/main/java/forge/view/SplashFrame.java -text diff --git a/src/main/java/forge/control/FControl.java b/src/main/java/forge/control/FControl.java index cf93b7d88c6..ff3e7e6d87c 100644 --- a/src/main/java/forge/control/FControl.java +++ b/src/main/java/forge/control/FControl.java @@ -64,11 +64,9 @@ import forge.gui.match.controllers.CMessage; import forge.gui.match.controllers.CStack; import forge.gui.match.nonsingleton.VField; import forge.gui.match.views.VAntes; -import forge.gui.menubar.FMenuBar; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.ForgeMenu; import forge.gui.toolbox.FSkin; import forge.net.FServer; -import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; import forge.properties.NewConstants; import forge.quest.QuestController; @@ -88,10 +86,11 @@ import forge.view.FView; public enum FControl implements KeyEventDispatcher { instance; - private FMenuBar menuBar; + private ForgeMenu forgeMenu; private List shortcuts; private JLayeredPane display; private Screens state = Screens.UNKNOWN; + private boolean altKeyLastDown; private WindowListener waDefault, waConcede, waLeaveBazaar, waLeaveEditor; @@ -174,7 +173,7 @@ public enum FControl implements KeyEventDispatcher { // Preloads skin components (using progress bar). FSkin.loadFull(true); - createMenuBar(); + forgeMenu = new ForgeMenu(); this.shortcuts = KeyboardShortcuts.attachKeyboardShortcuts(); this.display = FView.SINGLETON_INSTANCE.getLpnDocument(); @@ -217,13 +216,8 @@ public enum FControl implements KeyEventDispatcher { manager.addKeyEventDispatcher(this); } - private void createMenuBar() { - this.menuBar = new FMenuBar(Singletons.getView().getFrame()); - this.menuBar.setVisible(MenuUtil.isMenuBarVisible()); - } - - public FMenuBar getMenuBar() { - return this.menuBar; + public ForgeMenu getForgeMenu() { + return this.forgeMenu; } /** @@ -486,27 +480,33 @@ public enum FControl implements KeyEventDispatcher { */ @Override public boolean dispatchKeyEvent(KeyEvent e) { - // Toggle menu bar visibility using F1 key. - if (e.getKeyCode() == KeyEvent.VK_F1 && e.getID() == KeyEvent.KEY_RELEASED) { - toggleMenuBarVisibility(); - return true; - } else { - //Allow the event to be redispatched - return false; - } - } - - private void toggleMenuBarVisibility() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - ForgePreferences prefs = Singletons.getModel().getPreferences(); - boolean isHidden = !prefs.getPrefBoolean(FPref.UI_HIDE_MENUBAR); - menuBar.setVisible(!isHidden); - prefs.setPref(FPref.UI_HIDE_MENUBAR, String.valueOf(isHidden)); - prefs.save(); + // Show Forge menu if Alt key pressed without modifiers and released without pressing any other keys in between + if (e.getKeyCode() == KeyEvent.VK_ALT) { + if (e.getID() == KeyEvent.KEY_RELEASED) { + if (altKeyLastDown) { + forgeMenu.show(true); + return true; + } } - }); + else if (e.getID() == KeyEvent.KEY_PRESSED && e.getModifiers() == KeyEvent.ALT_MASK) { + altKeyLastDown = true; + } + } + else { + altKeyLastDown = false; + if (e.getID() == KeyEvent.KEY_PRESSED) { + if (forgeMenu.handleKeyEvent(e)) { //give Forge menu the chance to handle the key event + return true; + } + } + else if (e.getID() == KeyEvent.KEY_RELEASED) { + if (e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU) { + forgeMenu.show(); + } + } + } + //Allow the event to be redispatched + return false; } } diff --git a/src/main/java/forge/gui/SOverlayUtils.java b/src/main/java/forge/gui/SOverlayUtils.java index e9239794890..2cbc18f515f 100644 --- a/src/main/java/forge/gui/SOverlayUtils.java +++ b/src/main/java/forge/gui/SOverlayUtils.java @@ -126,7 +126,7 @@ public final class SOverlayUtils { private static Component prevFocusOwner; public static void showOverlay() { - Singletons.getControl().getMenuBar().setEnabled(false); + Singletons.getControl().getForgeMenu().setEnabled(false); prevFocusOwner = FocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); FOverlay.SINGLETON_INSTANCE.getPanel().setVisible(true); // ensure no background element has focus @@ -138,7 +138,7 @@ public final class SOverlayUtils { * Removes child components and closes overlay. */ public static void hideOverlay() { - Singletons.getControl().getMenuBar().setEnabled(true); + Singletons.getControl().getForgeMenu().setEnabled(true); FOverlay.SINGLETON_INSTANCE.getPanel().removeAll(); FOverlay.SINGLETON_INSTANCE.getPanel().setVisible(false); if (null != prevFocusOwner) { diff --git a/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java b/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java index e8e2d78b9f4..0468e708650 100644 --- a/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java +++ b/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java @@ -58,7 +58,7 @@ import forge.gui.deckeditor.views.VCardCatalog; import forge.gui.framework.ICDoc; import forge.gui.match.controllers.CDetail; import forge.gui.match.controllers.CPicture; -import forge.gui.menubar.IMenuProvider; +import forge.gui.menus.IMenuProvider; import forge.gui.toolbox.FLabel; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.itemmanager.ItemManager; @@ -554,7 +554,7 @@ public enum CDeckEditorUI implements ICDoc, IMenuProvider { */ @Override public void initialize() { - Singletons.getControl().getMenuBar().setupMenuBar(this); + Singletons.getControl().getForgeMenu().setProvider(this); } /* (non-Javadoc) diff --git a/src/main/java/forge/gui/framework/SResizingUtil.java b/src/main/java/forge/gui/framework/SResizingUtil.java index 098a5707883..5b8fb75c9ce 100644 --- a/src/main/java/forge/gui/framework/SResizingUtil.java +++ b/src/main/java/forge/gui/framework/SResizingUtil.java @@ -19,9 +19,13 @@ import java.util.Set; import javax.swing.JPanel; +import forge.Singletons; import forge.gui.FNetOverlay; import forge.gui.toolbox.FAbsolutePositioner; import forge.gui.toolbox.FOverlay; +import forge.properties.ForgePreferences; +import forge.properties.ForgePreferences.FPref; +import forge.view.FNavigationBar; import forge.view.FStatusBar; import forge.view.FView; @@ -115,19 +119,25 @@ public final class SResizingUtil { public static void resizeWindow() { final List cells = FView.SINGLETON_INSTANCE.getDragCells(); + final FNavigationBar navigationBar = FView.SINGLETON_INSTANCE.getNavigationBar(); final JPanel pnlContent = FView.SINGLETON_INSTANCE.getPnlContent(); final JPanel pnlInsets = FView.SINGLETON_INSTANCE.getPnlInsets(); final FStatusBar statusBar = FView.SINGLETON_INSTANCE.getStatusBar(); - Rectangle mainBounds = FView.SINGLETON_INSTANCE.getFrame().getInnerPane().getContentPane().getBounds(); + Rectangle mainBounds = FView.SINGLETON_INSTANCE.getFrame().getContentPane().getBounds(); mainBounds.y = 0; // Play nicely with MenuBar if visible or not. FAbsolutePositioner.SINGLETON_INSTANCE.containerResized(mainBounds); FOverlay.SINGLETON_INSTANCE.getPanel().setBounds(mainBounds); FNetOverlay.SINGLETON_INSTANCE.containerResized(mainBounds); - final int statusBarHeight = statusBar.getPreferredSize().height; + final ForgePreferences prefs = Singletons.getModel().getPreferences(); + final int navigationBarHeight = prefs.getPrefBoolean(FPref.UI_HIDE_TITLE_BAR) ? 0 : navigationBar.getPreferredSize().height; + final int statusBarHeight = prefs.getPrefBoolean(FPref.UI_HIDE_STATUS_BAR) ? 0 : statusBar.getPreferredSize().height; - pnlInsets.setBounds(mainBounds.x, mainBounds.y, mainBounds.width, mainBounds.height - statusBarHeight); + navigationBar.setBounds(mainBounds.x, mainBounds.y, mainBounds.width, navigationBarHeight); + navigationBar.validate(); + + pnlInsets.setBounds(mainBounds.x, mainBounds.y + navigationBarHeight, mainBounds.width, mainBounds.height - navigationBarHeight - statusBarHeight); pnlInsets.validate(); statusBar.setBounds(mainBounds.x, mainBounds.y + mainBounds.height - statusBarHeight, mainBounds.width, statusBarHeight); diff --git a/src/main/java/forge/gui/home/CHomeUI.java b/src/main/java/forge/gui/home/CHomeUI.java index 12c46a6fe52..bc8282db12d 100644 --- a/src/main/java/forge/gui/home/CHomeUI.java +++ b/src/main/java/forge/gui/home/CHomeUI.java @@ -13,8 +13,8 @@ import forge.gui.deckeditor.controllers.CEditorConstructed; import forge.gui.framework.EDocID; import forge.gui.framework.ICDoc; import forge.gui.home.sanctioned.VSubmenuConstructed; -import forge.gui.menubar.IMenuProvider; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.IMenuProvider; +import forge.gui.menus.MenuUtil; import forge.net.FServer; import forge.net.NetServer; import forge.properties.ForgePreferences; @@ -47,7 +47,7 @@ public enum CHomeUI implements ICDoc, IMenuProvider { if (previousDoc != null) { if (!previousDoc.equals(id0.getDoc().getLayoutControl())) { - MenuUtil.setupMenuBar(null); + MenuUtil.setMenuProvider(null); } } @@ -124,7 +124,7 @@ public enum CHomeUI implements ICDoc, IMenuProvider { } private void setupMyMenuBar() { - Singletons.getControl().getMenuBar().setupMenuBar(this); + Singletons.getControl().getForgeMenu().setProvider(this); } /* (non-Javadoc) diff --git a/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java b/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java index 4414a23c9b6..b12f36741c9 100644 --- a/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java +++ b/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java @@ -20,8 +20,8 @@ import forge.game.player.LobbyPlayer; import forge.gui.SOverlayUtils; import forge.gui.deckchooser.DecksComboBox.DeckType; import forge.gui.framework.ICDoc; -import forge.gui.menubar.IMenuProvider; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.IMenuProvider; +import forge.gui.menus.MenuUtil; import forge.gui.toolbox.FComboBox; import forge.net.FServer; import forge.net.Lobby; @@ -65,7 +65,7 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider { @Override public void update() { - MenuUtil.setupMenuBar(this); + MenuUtil.setMenuProvider(this); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { view.getBtnStart().requestFocusInWindow(); } diff --git a/src/main/java/forge/gui/home/sanctioned/ConstructedGameMenu.java b/src/main/java/forge/gui/home/sanctioned/ConstructedGameMenu.java index 0dacbc6c81b..359e25796b3 100644 --- a/src/main/java/forge/gui/home/sanctioned/ConstructedGameMenu.java +++ b/src/main/java/forge/gui/home/sanctioned/ConstructedGameMenu.java @@ -9,7 +9,7 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import forge.Singletons; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.MenuUtil; import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; diff --git a/src/main/java/forge/gui/match/CMatchUI.java b/src/main/java/forge/gui/match/CMatchUI.java index b52db1a3b47..86254444e50 100644 --- a/src/main/java/forge/gui/match/CMatchUI.java +++ b/src/main/java/forge/gui/match/CMatchUI.java @@ -60,7 +60,7 @@ import forge.gui.match.nonsingleton.VCommand; import forge.gui.match.nonsingleton.VField; import forge.gui.match.nonsingleton.VHand; import forge.gui.match.views.VPlayers; -import forge.gui.menubar.IMenuProvider; +import forge.gui.menus.IMenuProvider; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.SkinImage; import forge.gui.toolbox.special.PhaseLabel; @@ -422,7 +422,7 @@ public enum CMatchUI implements ICDoc, IMenuProvider { */ @Override public void initialize() { - Singletons.getControl().getMenuBar().setupMenuBar(this); + Singletons.getControl().getForgeMenu().setProvider(this); } /* (non-Javadoc) diff --git a/src/main/java/forge/gui/match/menus/CardOverlaysMenu.java b/src/main/java/forge/gui/match/menus/CardOverlaysMenu.java index 39aa1c8a1a6..caa4989a4ad 100644 --- a/src/main/java/forge/gui/match/menus/CardOverlaysMenu.java +++ b/src/main/java/forge/gui/match/menus/CardOverlaysMenu.java @@ -13,7 +13,7 @@ import javax.swing.SwingUtilities; import forge.Singletons; import forge.gui.match.CMatchUI; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.MenuUtil; import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; diff --git a/src/main/java/forge/gui/match/menus/DevModeMenu.java b/src/main/java/forge/gui/match/menus/DevModeMenu.java index 520dc41d519..2c664a03118 100644 --- a/src/main/java/forge/gui/match/menus/DevModeMenu.java +++ b/src/main/java/forge/gui/match/menus/DevModeMenu.java @@ -12,7 +12,7 @@ import javax.swing.event.MenuListener; import forge.Singletons; import forge.gui.match.controllers.CDev; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.MenuUtil; import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; @@ -93,11 +93,11 @@ public class DevModeMenu implements ActionListener { return new MenuListener() { @Override public void menuSelected(MenuEvent arg0) { - Singletons.getControl().getMenuBar().setStatusText("Options for testing during development"); + Singletons.getView().getStatusBar().setStatusText("Options for testing during development"); } @Override public void menuDeselected(MenuEvent arg0) { - Singletons.getControl().getMenuBar().setStatusText(""); + Singletons.getView().getStatusBar().setStatusText(""); } @Override public void menuCanceled(MenuEvent arg0) { } diff --git a/src/main/java/forge/gui/match/menus/GameMenu.java b/src/main/java/forge/gui/match/menus/GameMenu.java index f15169dea70..3afcf0b8767 100644 --- a/src/main/java/forge/gui/match/menus/GameMenu.java +++ b/src/main/java/forge/gui/match/menus/GameMenu.java @@ -13,7 +13,7 @@ import javax.swing.JRadioButtonMenuItem; import forge.Singletons; import forge.gui.match.controllers.CDock; -import forge.gui.menubar.MenuUtil; +import forge.gui.menus.MenuUtil; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.SkinIcon; import forge.gui.toolbox.FSkin.SkinProp; diff --git a/src/main/java/forge/gui/menubar/FMenuBar.java b/src/main/java/forge/gui/menubar/FMenuBar.java deleted file mode 100644 index 0e2c8b02609..00000000000 --- a/src/main/java/forge/gui/menubar/FMenuBar.java +++ /dev/null @@ -1,120 +0,0 @@ -package forge.gui.menubar; - -import java.awt.Component; -import java.awt.Dimension; -import java.util.List; - -import javax.swing.Box; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; - -import forge.gui.menus.ForgeMenu; -import forge.gui.menus.HelpMenu; -import forge.gui.menus.LayoutMenu; -import forge.gui.toolbox.FSkin; -import forge.gui.toolbox.FSkin.JLabelSkin; -import forge.view.FFrame; - -@SuppressWarnings("serial") -public class FMenuBar extends JMenuBar { - private final FFrame frame; - private String statusText; - private JLabel lblStatus; - private IMenuProvider provider; - - public FMenuBar(FFrame f) { - this.frame = f; - setVisible(false); //hide by default until prefs decide whether to show it - super.setVisible(true); //ensure super is visible since setVisible overriden to only set height to 0 to hide - f.getInnerPane().setJMenuBar(this); - refresh(); - setStatusText(""); //set default status text - } - - public void setupMenuBar(IMenuProvider provider0) { - provider = provider0; - refresh(); - } - - public void refresh() { - removeAll(); - add(ForgeMenu.getMenu()); - addProviderMenus(); - add(LayoutMenu.getMenu()); - add(HelpMenu.getMenu()); - addStatusLabel(); - repaintMenuBar(); - } - - /** - * Ensures that MenuBar is repainted correctly. - *

- * !! Both statements are required - do not alter !! - */ - private void repaintMenuBar() { - validate(); - repaint(); - } - - /** - * Adds a label to the right-hand side of the MenuBar which can - * be used to show hints or status information. - */ - private void addStatusLabel() { - add(Box.createHorizontalGlue()); // align right hack/patch. - lblStatus = new JLabel(statusText); - JLabelSkin labelSkin = FSkin.get(lblStatus); - if (FSkin.isLookAndFeelSet()) { - labelSkin.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); - } - else { //ensure status is visible on default menu bar - labelSkin.setForeground(getForeground()); - } - labelSkin.setFont(FSkin.getItalicFont(11)); - lblStatus.setOpaque(false); - add(lblStatus); - } - - public void setStatusText(String text) { - statusText = text.trim(); - if (statusText.isEmpty()) { - statusText = "F1 : hide menu"; //show shortcut to hide menu if no other status to show - } - statusText += " "; //add padding from right edge of menu bar - lblStatus.setText(statusText); - } - - private void addProviderMenus() { - if (provider != null) { - List menus = provider.getMenus(); - if (menus != null) { - for (JMenu m : menus) { - m.setBorderPainted(false); - add(m); - } - } - } - } - - /* (non-Javadoc) - * @see javax.swing.JComponent#setEnabled(boolean) - */ - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - for (Component c : getComponents()) { - c.setEnabled(enabled); - } - } - - /* (non-Javadoc) - * @see javax.swing.JComponent#setVisible(boolean) - */ - @Override - public void setVisible(boolean visible) { - //use height 0 to hide rather than setting visible to false to allow menu item accelerators to work - setPreferredSize(new Dimension(this.frame.getWidth(), visible ? 22 : 0)); - revalidate(); - } -} diff --git a/src/main/java/forge/gui/menus/ForgeMenu.java b/src/main/java/forge/gui/menus/ForgeMenu.java index 50019ff512c..b337e91c2e1 100644 --- a/src/main/java/forge/gui/menus/ForgeMenu.java +++ b/src/main/java/forge/gui/menus/ForgeMenu.java @@ -1,49 +1,110 @@ package forge.gui.menus; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.util.HashMap; +import java.util.List; + import javax.swing.JMenu; import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; + import forge.Singletons; import forge.control.RestartUtil; import forge.control.FControl.Screens; -import forge.gui.menubar.MenuUtil; +import forge.util.TypeUtil; -public final class ForgeMenu { - private ForgeMenu() { } - - public static JMenu getMenu() { - JMenu menu = new JMenu("Forge"); - menu.setMnemonic(KeyEvent.VK_F); - menu.add(getMenuItem_Restart()); - menu.add(getMenuItem_Exit()); - return menu; +@SuppressWarnings("serial") +public class ForgeMenu extends JPopupMenu { + private static final int minItemWidth = 100; + private static final int itemHeight = 25; + + private IMenuProvider provider; + private static HashMap activeShortcuts = new HashMap(); + + public ForgeMenu() { + refresh(); } - private static JMenuItem getMenuItem_Exit() { - JMenuItem menuItem = new JMenuItem("Exit"); - menuItem.addActionListener(getExitAction()); - return menuItem; + @Override + public void show() { + show(false); } - private static ActionListener getExitAction() { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!isHomeScreenActive()) { - String userPrompt = "Please confirm you want to close Forge.\n\n"; - if (!MenuUtil.getUserConfirmation(userPrompt, "Exit Forge")) { - return; - } + @Override + public void show(boolean hideIfAlreadyShown) { + Singletons.getView().getNavigationBar().showForgeMenu(hideIfAlreadyShown); + } + + public void setProvider(IMenuProvider provider0) { + provider = provider0; + refresh(); + } + + public void refresh() { + activeShortcuts.clear(); + removeAll(); + if (provider != null) { + List menus = provider.getMenus(); + if (menus != null) { + for (JMenu m : menus) { + m.setBorderPainted(false); + add(m); } - System.exit(0); } - }; + } + add(LayoutMenu.getMenu()); + add(HelpMenu.getMenu()); + addSeparator(); + add(getMenuItem_Restart()); + add(getMenuItem_Exit()); + } + + @Override + public JMenuItem add(JMenuItem item) { + item = super.add(item); + setupItem(item); + return item; + } + + private void setupMenu(JMenu menu) { + for (int i = 0; i < menu.getItemCount(); i++) { + setupItem(menu.getItem(i)); + } + } + + private void setupItem(JMenuItem item) { + if (item == null) { return; } + + item.setPreferredSize(new Dimension(Math.max(item.getPreferredSize().width, minItemWidth), itemHeight)); + + KeyStroke shortcut = item.getAccelerator(); + if (shortcut != null) { + activeShortcuts.put(shortcut, item); + } + + JMenu subMenu = TypeUtil.safeCast(item, JMenu.class); + if (subMenu != null) { + setupMenu(subMenu); + } + } + + public boolean handleKeyEvent(KeyEvent e) { + JMenuItem item = activeShortcuts.get(KeyStroke.getKeyStrokeForEvent(e)); + if (item != null) { + setVisible(false); //ensure menu doesn't stay open if currently open + item.doClick(); + return true; + } + return false; } private static JMenuItem getMenuItem_Restart() { - JMenuItem menuItem = new JMenuItem("Restart"); + JMenuItem menuItem = new JMenuItem("Restart"); + menuItem.setMnemonic(KeyEvent.VK_R); menuItem.addActionListener(getRestartAction()); return menuItem; } @@ -63,8 +124,29 @@ public final class ForgeMenu { }; } + private static JMenuItem getMenuItem_Exit() { + JMenuItem menuItem = new JMenuItem("Exit"); + menuItem.setMnemonic(KeyEvent.VK_X); + menuItem.addActionListener(getExitAction()); + return menuItem; + } + + private static ActionListener getExitAction() { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!isHomeScreenActive()) { + String userPrompt = "Please confirm you want to close Forge.\n\n"; + if (!MenuUtil.getUserConfirmation(userPrompt, "Exit Forge")) { + return; + } + } + System.exit(0); + } + }; + } + private static boolean isHomeScreenActive() { return Singletons.getControl().getState() == Screens.HOME_SCREEN; } - } diff --git a/src/main/java/forge/gui/menus/HelpMenu.java b/src/main/java/forge/gui/menus/HelpMenu.java index b771160fb6d..1d864dd13cb 100644 --- a/src/main/java/forge/gui/menus/HelpMenu.java +++ b/src/main/java/forge/gui/menus/HelpMenu.java @@ -9,8 +9,8 @@ import java.io.IOException; import javax.swing.JMenu; import javax.swing.JMenuItem; +import javax.swing.KeyStroke; -import forge.gui.menubar.MenuUtil; import forge.util.FileUtil; public final class HelpMenu { @@ -47,7 +47,7 @@ public final class HelpMenu { JMenu mnu = new JMenu("Getting Started"); mnu.add(getMenuItem_HowToPlayFile()); mnu.addSeparator(); - mnu.add(getMenuItem_UrlLink("Forge Wiki", "http://www.slightlymagic.net/wiki/Forge")); + mnu.add(getMenuItem_UrlLink("Forge Wiki", "http://www.slightlymagic.net/wiki/Forge", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0))); mnu.add(getMenuItem_UrlLink("What is Forge?", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=468")); return mnu; } @@ -112,14 +112,19 @@ public final class HelpMenu { Desktop.getDesktop().open(file); } } - - + private static JMenuItem getMenuItem_UrlLink(String caption, String url) { JMenuItem menuItem = new JMenuItem(caption); menuItem.addActionListener(getLaunchUrlAction(url)); return menuItem; } + private static JMenuItem getMenuItem_UrlLink(String caption, String url, KeyStroke accelerator) { + JMenuItem menuItem = getMenuItem_UrlLink(caption, url); + menuItem.setAccelerator(accelerator); + return menuItem; + } + private static ActionListener getLaunchUrlAction(final String url) { return new ActionListener() { @Override diff --git a/src/main/java/forge/gui/menubar/IMenuProvider.java b/src/main/java/forge/gui/menus/IMenuProvider.java similarity index 92% rename from src/main/java/forge/gui/menubar/IMenuProvider.java rename to src/main/java/forge/gui/menus/IMenuProvider.java index 061aacf03c3..b43e575c558 100644 --- a/src/main/java/forge/gui/menubar/IMenuProvider.java +++ b/src/main/java/forge/gui/menus/IMenuProvider.java @@ -1,4 +1,4 @@ -package forge.gui.menubar; +package forge.gui.menus; import java.util.List; diff --git a/src/main/java/forge/gui/menus/LayoutMenu.java b/src/main/java/forge/gui/menus/LayoutMenu.java index e009fdc8139..7450e7135e8 100644 --- a/src/main/java/forge/gui/menus/LayoutMenu.java +++ b/src/main/java/forge/gui/menus/LayoutMenu.java @@ -17,8 +17,8 @@ import forge.control.FControl.Screens; import forge.gui.GuiChoose; import forge.gui.MouseUtil; import forge.gui.MouseUtil.MouseCursor; +import forge.gui.framework.SResizingUtil; import forge.gui.match.controllers.CDock; -import forge.gui.menubar.MenuUtil; import forge.gui.toolbox.FSkin; import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; @@ -32,9 +32,9 @@ import forge.view.FView; public final class LayoutMenu { private LayoutMenu() { } - private static CDock controller = CDock.SINGLETON_INSTANCE; + private static final CDock controller = CDock.SINGLETON_INSTANCE; private static Screens currentScreen; - private static ForgePreferences prefs = Singletons.getModel().getPreferences(); + private static final ForgePreferences prefs = Singletons.getModel().getPreferences(); private static boolean showIcons = false; public static JMenu getMenu() { @@ -58,6 +58,7 @@ public final class LayoutMenu { private static JMenu getMenu_ViewOptions() { JMenu menu = new JMenu("View"); menu.add(getMenuItem_ShowTitleBar()); + menu.add(getMenuItem_ShowStatusBar()); if (currentScreen != Screens.HOME_SCREEN) { menu.add(getMenuItem_ShowTabs()); } @@ -139,14 +140,15 @@ public final class LayoutMenu { boolean showTabs = menuItem.getState(); FView.SINGLETON_INSTANCE.refreshAllCellLayouts(showTabs); prefs.setPref(FPref.UI_HIDE_GAME_TABS, !showTabs); + prefs.save(); } }; } private static JMenuItem getMenuItem_ShowTitleBar() { - final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem("Titlebar"); + final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem("Title Bar"); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0)); - menuItem.setState(Singletons.getView().getFrame().getShowTitleBar()); + menuItem.setState(!prefs.getPrefBoolean(FPref.UI_HIDE_TITLE_BAR)); menuItem.addActionListener(getShowTitleBarAction(menuItem)); return menuItem; } @@ -155,10 +157,32 @@ public final class LayoutMenu { @Override public void actionPerformed(ActionEvent e) { boolean showTitleBar = menuItem.getState(); + prefs.setPref(FPref.UI_HIDE_TITLE_BAR, !showTitleBar); + prefs.save(); Singletons.getView().getFrame().setShowTitleBar(showTitleBar); } }; } + + private static JMenuItem getMenuItem_ShowStatusBar() { + final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem("Status Bar"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F12, 0)); + menuItem.setState(!prefs.getPrefBoolean(FPref.UI_HIDE_STATUS_BAR)); + menuItem.addActionListener(getShowStatusBarAction(menuItem)); + return menuItem; + } + private static ActionListener getShowStatusBarAction(final JCheckBoxMenuItem menuItem) { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean showStatusBar = menuItem.getState(); + prefs.setPref(FPref.UI_HIDE_STATUS_BAR, !showStatusBar); + prefs.save(); + Singletons.getView().getStatusBar().setVisible(showStatusBar); + SResizingUtil.resizeWindow(); + } + }; + } private static JMenuItem getMenuItem_SaveLayout() { JMenuItem menuItem = new JMenuItem("Save Current Layout"); diff --git a/src/main/java/forge/gui/menubar/MenuUtil.java b/src/main/java/forge/gui/menus/MenuUtil.java similarity index 74% rename from src/main/java/forge/gui/menubar/MenuUtil.java rename to src/main/java/forge/gui/menus/MenuUtil.java index a45c06b4ae4..f6c333d2a92 100644 --- a/src/main/java/forge/gui/menubar/MenuUtil.java +++ b/src/main/java/forge/gui/menus/MenuUtil.java @@ -1,4 +1,4 @@ -package forge.gui.menubar; +package forge.gui.menus; import java.awt.Toolkit; import java.io.IOException; @@ -14,21 +14,12 @@ import forge.Singletons; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.SkinProp; import forge.gui.toolbox.imaging.ImageUtil; -import forge.properties.ForgePreferences; -import forge.properties.ForgePreferences.FPref; public final class MenuUtil { private MenuUtil() { } - private static ForgePreferences prefs = Singletons.getModel().getPreferences(); - // Get appropriate OS standard accelerator key for menu shortcuts. - private static final int DEFAULT_MenuShortcutKeyMask = - Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - - public static boolean isMenuBarVisible() { - return !prefs.getPrefBoolean(FPref.UI_HIDE_MENUBAR); - } + private static final int DEFAULT_MenuShortcutKeyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); public static void openUrlInBrowser(String url) { try { @@ -61,8 +52,8 @@ public final class MenuUtil { return (reply == JOptionPane.YES_OPTION); } - public static void setupMenuBar(IMenuProvider provider) { - Singletons.getControl().getMenuBar().setupMenuBar(provider); + public static void setMenuProvider(IMenuProvider provider) { + Singletons.getControl().getForgeMenu().setProvider(provider); } public static void setMenuHint(final JMenuItem menu, final String hint) { menu.addChangeListener(new ChangeListener() { @@ -70,9 +61,9 @@ public final class MenuUtil { public void stateChanged(ChangeEvent e) { JMenuItem item = (JMenuItem) e.getSource(); if (item.isArmed() || (item.isSelected() && e.getSource() instanceof JMenu)) { - Singletons.getControl().getMenuBar().setStatusText(hint); + Singletons.getView().getStatusBar().setStatusText(hint); } else { - Singletons.getControl().getMenuBar().setStatusText(""); + Singletons.getView().getStatusBar().setStatusText(""); } } }); diff --git a/src/main/java/forge/gui/toolbox/FSkin.java b/src/main/java/forge/gui/toolbox/FSkin.java index dc731135880..5e68569a0fe 100644 --- a/src/main/java/forge/gui/toolbox/FSkin.java +++ b/src/main/java/forge/gui/toolbox/FSkin.java @@ -1631,7 +1631,7 @@ public enum FSkin { ComponentSkin.reapplyAll(); //refresh certain components skinned via look and feel - Singletons.getControl().getMenuBar().refresh(); + Singletons.getControl().getForgeMenu().refresh(); FComboBoxWrapper.refreshAllSkins(); FComboBoxPanel.refreshAllSkins(); CSubmenuPreferences.SINGLETON_INSTANCE.updateCurrentSkin(); diff --git a/src/main/java/forge/properties/ForgePreferences.java b/src/main/java/forge/properties/ForgePreferences.java index baa00599e1e..5e40dee5996 100644 --- a/src/main/java/forge/properties/ForgePreferences.java +++ b/src/main/java/forge/properties/ForgePreferences.java @@ -66,7 +66,8 @@ public class ForgePreferences extends PreferencesStore { UI_CLONE_MODE_SOURCE ("false"), /** */ UI_MATCH_IMAGE_VISIBLE ("true"), UI_THEMED_COMBOBOX ("true"), - UI_HIDE_MENUBAR ("false"), // Dev setting only - cannot be set from GUI. + UI_HIDE_TITLE_BAR ("false"), + UI_HIDE_STATUS_BAR ("false"), UI_HIDE_GAME_TABS ("false"), // Visibility of tabs in match screen. UI_FOR_TOUCHSCREN("false"), diff --git a/src/main/java/forge/view/FFrame.java b/src/main/java/forge/view/FFrame.java index b90780aba91..509ec26b104 100644 --- a/src/main/java/forge/view/FFrame.java +++ b/src/main/java/forge/view/FFrame.java @@ -15,6 +15,7 @@ import javax.swing.JFrame; import javax.swing.JRootPane; import javax.swing.SwingUtilities; +import forge.gui.framework.SResizingUtil; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.Colors; import forge.gui.toolbox.FSkin.CompoundSkinBorder; @@ -27,27 +28,29 @@ public class FFrame extends JFrame { private Dimension sizeBeforeResize; private Point mouseDownLoc; private int resizeCursor; - private FTitleBar titleBar; + private FTitleBarBase titleBar; private boolean maximized, showTitleBar; - private final JRootPane innerPane = new JRootPane(); public FFrame() { setUndecorated(true); - setContentPane(innerPane); } public void initialize() { + initialize(new FTitleBar(this), true); //show titlebar by default + } + + public void initialize(FTitleBarBase titleBar0, boolean showTitleBar0) { // Frame border updateBorder(); addResizeSupport(); // Title bar - this.titleBar = new FTitleBar(this); - this.setShowTitleBar(true); //show titlebar by default + this.titleBar = titleBar0; + this.setShowTitleBar(showTitleBar0); addMoveSupport(); } - public FTitleBar getTitleBar() { + public FTitleBarBase getTitleBar() { return this.titleBar; } @@ -59,9 +62,12 @@ public class FFrame extends JFrame { if (this.showTitleBar == showTitleBar0) { return; } this.showTitleBar = showTitleBar0; this.titleBar.setVisible(showTitleBar0); - if (!showTitleBar0) { + if (!showTitleBar0 && !this.getMaximized()) { this.setMaximized(true); //only support hidden titlebar if maximized } + else { + SResizingUtil.resizeWindow(); //ensure window layout updated to account for showing titlebar + } } @Override @@ -152,10 +158,6 @@ public class FFrame extends JFrame { } } - public JRootPane getInnerPane() { - return innerPane; - } - private void addMoveSupport() { this.titleBar.addMouseListener(new MouseAdapter() { @Override diff --git a/src/main/java/forge/view/FNavigationBar.java b/src/main/java/forge/view/FNavigationBar.java new file mode 100644 index 00000000000..e71b181f9f2 --- /dev/null +++ b/src/main/java/forge/view/FNavigationBar.java @@ -0,0 +1,86 @@ +package forge.view; + +import java.awt.Dimension; +import java.awt.Image; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.SpringLayout; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; + +import forge.Singletons; +import forge.gui.menus.ForgeMenu; +import forge.gui.toolbox.FButton; +import forge.gui.toolbox.FSkin; + +@SuppressWarnings("serial") +public class FNavigationBar extends FTitleBarBase { + + private final FButton btnForge = new FButton("Forge"); + private final ForgeMenu forgeMenu = Singletons.getControl().getForgeMenu(); + private long timeMenuHidden = 0; + + public FNavigationBar(FFrame f) { + super(f); + btnForge.setFocusable(false); + btnForge.setPreferredSize(new Dimension(100, 23)); + setIconImage(this.frame.getIconImage()); //set default icon image based on frame icon image + FSkin.get(btnForge).setForeground(foreColor); + addControls(); + } + + @Override + protected void addControls() { + add(btnForge); + layout.putConstraint(SpringLayout.WEST, btnForge, 1, SpringLayout.WEST, this); + layout.putConstraint(SpringLayout.NORTH, btnForge, 1, SpringLayout.NORTH, this); + addForgeButtonListeners(); + super.addControls(); + } + + private void addForgeButtonListeners() { + btnForge.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (System.currentTimeMillis() - timeMenuHidden > 250) { //time comparsion needed clicking button a second time to hide menu + showForgeMenu(true); + } + } + }); + forgeMenu.addPopupMenuListener(new PopupMenuListener() { + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent) { + btnForge.setToggled(false); + timeMenuHidden = System.currentTimeMillis(); + } + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {} + @Override + public void popupMenuCanceled(PopupMenuEvent popupMenuEvent) {} + }); + } + + public void showForgeMenu(boolean hideIfAlreadyShown) { + if (!btnForge.isToggled()) { + btnForge.setToggled(true); + forgeMenu.show(this, 1, this.getHeight()); + } + else if (hideIfAlreadyShown) { + forgeMenu.setVisible(false); + } + } + + @Override + public String getTitle() { + return "Forge"; + } + + @Override + public void setTitle(String title) { + } + + @Override + public void setIconImage(Image image) { + } +} diff --git a/src/main/java/forge/view/FStatusBar.java b/src/main/java/forge/view/FStatusBar.java index 74998f1abb2..aab73d03d2a 100644 --- a/src/main/java/forge/view/FStatusBar.java +++ b/src/main/java/forge/view/FStatusBar.java @@ -25,7 +25,7 @@ public class FStatusBar extends JPanel { private final JLabel lblStatus = new JLabel(); private final FDigitalClock clock = new FDigitalClock(); - public FStatusBar(FFrame f) { + public FStatusBar(FFrame f, boolean visible0) { this.frame = f; setPreferredSize(new Dimension(f.getWidth(), 18)); setLayout(this.layout); @@ -42,6 +42,8 @@ public class FStatusBar extends JPanel { add(clock); layout.putConstraint(SpringLayout.EAST, clock, -4, SpringLayout.EAST, this); layout.putConstraint(SpringLayout.NORTH, clock, 0, SpringLayout.NORTH, lblStatus); + + this.setVisible(visible0); } public void setStatusText(String text) { diff --git a/src/main/java/forge/view/FTitleBar.java b/src/main/java/forge/view/FTitleBar.java index 94d9a3c9353..7f05a912e97 100644 --- a/src/main/java/forge/view/FTitleBar.java +++ b/src/main/java/forge/view/FTitleBar.java @@ -1,87 +1,43 @@ package forge.view; -import java.awt.BasicStroke; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Image; -import java.awt.RenderingHints; -import java.awt.Toolkit; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.WindowEvent; - import javax.swing.ImageIcon; import javax.swing.JLabel; -import javax.swing.JMenuBar; import javax.swing.SpringLayout; -import javax.swing.SwingUtilities; - -import forge.gui.framework.ILocalRepaint; import forge.gui.toolbox.FSkin; -import forge.gui.toolbox.FSkin.Colors; -import forge.gui.toolbox.FSkin.JLabelSkin; -import forge.gui.toolbox.FSkin.SkinColor; @SuppressWarnings("serial") -public class FTitleBar extends JMenuBar { - private static final SkinColor foreColor = FSkin.getColor(Colors.CLR_TEXT); - private static final SkinColor backColor = FSkin.getColor(Colors.CLR_THEME2); - private static final SkinColor buttonHoverColor = backColor.stepColor(40); - private static final SkinColor buttonDownColor = backColor.stepColor(-40); - - private final FFrame frame; - private final SpringLayout layout = new SpringLayout(); +public class FTitleBar extends FTitleBarBase { private final JLabel lblTitle = new JLabel(); - private final MinimizeButton btnMinimize = new MinimizeButton(); - private final MaximizeButton btnMaximize = new MaximizeButton(); - private final CloseButton btnClose = new CloseButton(); - + public FTitleBar(FFrame f) { - this.frame = f; + super(f); f.setJMenuBar(this); - setPreferredSize(new Dimension(f.getWidth(), 26)); - setLayout(this.layout); - FSkin.get(this).setBackground(backColor); setTitle(f.getTitle()); //set default title based on frame title setIconImage(f.getIconImage()); //set default icon image based on frame icon image FSkin.get(lblTitle).setForeground(foreColor); - + addControls(); + } + + @Override + protected void addControls() { add(lblTitle); layout.putConstraint(SpringLayout.WEST, lblTitle, 1, SpringLayout.WEST, this); layout.putConstraint(SpringLayout.NORTH, lblTitle, 4, SpringLayout.NORTH, this); - - add(btnClose); - layout.putConstraint(SpringLayout.EAST, btnClose, 0, SpringLayout.EAST, this); - layout.putConstraint(SpringLayout.NORTH, btnClose, 0, SpringLayout.NORTH, this); - - add(btnMaximize); - layout.putConstraint(SpringLayout.EAST, btnMaximize, 0, SpringLayout.WEST, btnClose); - layout.putConstraint(SpringLayout.NORTH, btnMaximize, 0, SpringLayout.NORTH, btnClose); - - add(btnMinimize); - layout.putConstraint(SpringLayout.EAST, btnMinimize, 0, SpringLayout.WEST, btnMaximize); - layout.putConstraint(SpringLayout.NORTH, btnMinimize, 0, SpringLayout.NORTH, btnMaximize); - } - - public void handleMaximizedChanged() { - if (frame.getMaximized()) { - btnMaximize.setToolTipText("Restore Down"); - } - else { - btnMaximize.setToolTipText("Maximize"); - } - btnMaximize.repaintSelf(); + super.addControls(); } + @Override public String getTitle() { return this.lblTitle.getText(); } + @Override public void setTitle(String title) { this.lblTitle.setText(title); } + @Override public void setIconImage(Image image) { if (image != null) { this.lblTitle.setIcon(new ImageIcon(image.getScaledInstance(16, 16, Image.SCALE_AREA_AVERAGING))); @@ -90,168 +46,4 @@ public class FTitleBar extends JMenuBar { this.lblTitle.setIcon(null); } } - - public abstract class TitleBarButton extends JLabel implements ILocalRepaint { - protected JLabelSkin skin = FSkin.get(this); - private boolean pressed, hovered; - - private TitleBarButton() { - setPreferredSize(new Dimension(25, 25)); - addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - if (SwingUtilities.isLeftMouseButton(e)) { - pressed = true; - repaintSelf(); - } - } - @Override - public void mouseReleased(MouseEvent e) { - if (SwingUtilities.isLeftMouseButton(e)) { - if (pressed) { - pressed = false; - if (hovered) { //only handle click if mouse released over button - repaintSelf(); - onClick(); - } - } - } - } - @Override - public void mouseEntered(MouseEvent e) { - hovered = true; - repaintSelf(); - } - @Override - public void mouseExited(MouseEvent e) { - hovered = false; - repaintSelf(); - } - }); - } - - protected abstract void onClick(); - - @Override - public void repaintSelf() { - final Dimension d = this.getSize(); - repaint(0, 0, d.width, d.height); - } - - @Override - public void paintComponent(Graphics g) { - if (hovered) { - if (pressed) { - skin.setGraphicsColor(g, buttonDownColor); - g.fillRect(0, 0, getWidth(), getHeight()); - g.translate(1, 1); //translate icon to give pressed button look - } - else { - skin.setGraphicsColor(g, buttonHoverColor); - g.fillRect(0, 0, getWidth(), getHeight()); - } - } - } - } - - public class MinimizeButton extends TitleBarButton { - private MinimizeButton() { - setToolTipText("Minimize"); - } - @Override - protected void onClick() { - frame.setMinimized(true); - } - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - int thickness = 2; - int offsetX = 8; - int offsetY = 7; - int x1 = offsetX; - int x2 = getWidth() - offsetX; - int y = getHeight() - offsetY - thickness; - - Graphics2D g2d = (Graphics2D) g; - skin.setGraphicsColor(g2d, foreColor); - g2d.setStroke(new BasicStroke(thickness)); - g2d.drawLine(x1, y, x2, y); - } - } - - public class MaximizeButton extends TitleBarButton { - private MaximizeButton() { - setToolTipText("Maximize"); - } - @Override - protected void onClick() { - frame.setMaximized(!frame.getMaximized()); - } - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - int thickness = 2; - int offsetX = 7; - int offsetY = 8; - int x = offsetX; - int y = offsetY; - int width = getWidth() - 2 * offsetX; - int height = getHeight() - 2 * offsetY; - - Graphics2D g2d = (Graphics2D) g; - skin.setGraphicsColor(g2d, foreColor); - g2d.setStroke(new BasicStroke(thickness)); - - if (frame.getMaximized()) { //draw 2 rectangles offset if icon to restore window - x -= 1; - y += 2; - width -= 1; - height -= 1; - g2d.drawRect(x, y, width, height); - x += 3; - y -= 3; - //draw back rectangle as 4 lines so front rectangle doesn't show back rectangle through it - g2d.drawLine(x, y, x, y + 2); - g2d.drawLine(x, y, x + width, y); - x += width; - g2d.drawLine(x, y, x, y + height); - y += height; - g2d.drawLine(x - 2, y, x, y); - } - else { //otherwise just draw 1 rectangle if icon to maximize window - g2d.drawRect(x, y, width, height); - } - } - } - - public class CloseButton extends TitleBarButton { - private CloseButton() { - setToolTipText("Close"); - } - @Override - protected void onClick() { - WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING); - Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev); - } - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - int thickness = 2; - int offset = 7; - int x1 = offset; - int y1 = offset; - int x2 = getWidth() - offset - 1; - int y2 = getHeight() - offset - 1; - - Graphics2D g2d = (Graphics2D) g; - skin.setGraphicsColor(g2d, foreColor); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setStroke(new BasicStroke(thickness)); - g2d.drawLine(x1, y1, x2, y2); - g2d.drawLine(x2, y1, x1, y2); - } - } -} +} \ No newline at end of file diff --git a/src/main/java/forge/view/FTitleBarBase.java b/src/main/java/forge/view/FTitleBarBase.java new file mode 100644 index 00000000000..715ab6277ae --- /dev/null +++ b/src/main/java/forge/view/FTitleBarBase.java @@ -0,0 +1,250 @@ +package forge.view; + +import java.awt.BasicStroke; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowEvent; + +import javax.swing.JLabel; +import javax.swing.JMenuBar; +import javax.swing.SpringLayout; +import javax.swing.SwingUtilities; + +import forge.gui.framework.ILocalRepaint; +import forge.gui.toolbox.FSkin; +import forge.gui.toolbox.FSkin.Colors; +import forge.gui.toolbox.FSkin.JComponentSkin; +import forge.gui.toolbox.FSkin.JLabelSkin; +import forge.gui.toolbox.FSkin.SkinColor; + +@SuppressWarnings("serial") +public abstract class FTitleBarBase extends JMenuBar { + protected static final SkinColor foreColor = FSkin.getColor(Colors.CLR_TEXT); + protected static final SkinColor backColor = FSkin.getColor(Colors.CLR_THEME2); + protected static final SkinColor borderColor = backColor.stepColor(-80); + protected static final SkinColor buttonHoverColor = backColor.stepColor(40); + protected static final SkinColor buttonDownColor = backColor.stepColor(-40); + + protected final FFrame frame; + protected final JComponentSkin skin = FSkin.get(this); + protected final SpringLayout layout = new SpringLayout(); + private final MinimizeButton btnMinimize = new MinimizeButton(); + private final MaximizeButton btnMaximize = new MaximizeButton(); + private final CloseButton btnClose = new CloseButton(); + + protected FTitleBarBase(FFrame f) { + this.frame = f; + setVisible(true); //set to visible by default so preferred size set + setLayout(this.layout); + skin.setBackground(backColor); + skin.setMatteBorder(0, 0, 1, 0, borderColor); + } + + protected void addControls() { + add(btnClose); + layout.putConstraint(SpringLayout.EAST, btnClose, 0, SpringLayout.EAST, this); + layout.putConstraint(SpringLayout.NORTH, btnClose, 0, SpringLayout.NORTH, this); + + add(btnMaximize); + layout.putConstraint(SpringLayout.EAST, btnMaximize, 0, SpringLayout.WEST, btnClose); + layout.putConstraint(SpringLayout.NORTH, btnMaximize, 0, SpringLayout.NORTH, btnClose); + + add(btnMinimize); + layout.putConstraint(SpringLayout.EAST, btnMinimize, 0, SpringLayout.WEST, btnMaximize); + layout.putConstraint(SpringLayout.NORTH, btnMinimize, 0, SpringLayout.NORTH, btnMaximize); + } + + public abstract String getTitle(); + public abstract void setTitle(String title); + public abstract void setIconImage(Image image); + + public void handleMaximizedChanged() { + if (frame.getMaximized()) { + btnMaximize.setToolTipText("Restore Down"); + } + else { + btnMaximize.setToolTipText("Maximize"); + } + btnMaximize.repaintSelf(); + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#setVisible(boolean) + */ + @Override + public void setVisible(boolean visible) { + //use height 0 to hide rather than setting visible to false to allow menu item accelerators to work + setPreferredSize(new Dimension(this.frame.getWidth(), visible ? 26 : 0)); + revalidate(); + } + + public abstract class TitleBarButton extends JLabel implements ILocalRepaint { + protected JLabelSkin skin = FSkin.get(this); + private boolean pressed, hovered; + + private TitleBarButton() { + setPreferredSize(new Dimension(25, 25)); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (SwingUtilities.isLeftMouseButton(e)) { + pressed = true; + repaintSelf(); + } + } + @Override + public void mouseReleased(MouseEvent e) { + if (SwingUtilities.isLeftMouseButton(e)) { + if (pressed) { + pressed = false; + if (hovered) { //only handle click if mouse released over button + repaintSelf(); + onClick(); + } + } + } + } + @Override + public void mouseEntered(MouseEvent e) { + hovered = true; + repaintSelf(); + } + @Override + public void mouseExited(MouseEvent e) { + hovered = false; + repaintSelf(); + } + }); + } + + protected abstract void onClick(); + + @Override + public void repaintSelf() { + final Dimension d = this.getSize(); + repaint(0, 0, d.width, d.height); + } + + @Override + public void paintComponent(Graphics g) { + if (hovered) { + if (pressed) { + skin.setGraphicsColor(g, buttonDownColor); + g.fillRect(0, 0, getWidth(), getHeight()); + g.translate(1, 1); //translate icon to give pressed button look + } + else { + skin.setGraphicsColor(g, buttonHoverColor); + g.fillRect(0, 0, getWidth(), getHeight()); + } + } + } + } + + public class MinimizeButton extends TitleBarButton { + private MinimizeButton() { + setToolTipText("Minimize"); + } + @Override + protected void onClick() { + frame.setMinimized(true); + } + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + int thickness = 2; + int offsetX = 8; + int offsetY = 7; + int x1 = offsetX; + int x2 = getWidth() - offsetX; + int y = getHeight() - offsetY - thickness; + + Graphics2D g2d = (Graphics2D) g; + skin.setGraphicsColor(g2d, foreColor); + g2d.setStroke(new BasicStroke(thickness)); + g2d.drawLine(x1, y, x2, y); + } + } + + public class MaximizeButton extends TitleBarButton { + private MaximizeButton() { + setToolTipText("Maximize"); + } + @Override + protected void onClick() { + frame.setMaximized(!frame.getMaximized()); + } + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + int thickness = 2; + int offsetX = 7; + int offsetY = 8; + int x = offsetX; + int y = offsetY; + int width = getWidth() - 2 * offsetX; + int height = getHeight() - 2 * offsetY; + + Graphics2D g2d = (Graphics2D) g; + skin.setGraphicsColor(g2d, foreColor); + g2d.setStroke(new BasicStroke(thickness)); + + if (frame.getMaximized()) { //draw 2 rectangles offset if icon to restore window + x -= 1; + y += 2; + width -= 1; + height -= 1; + g2d.drawRect(x, y, width, height); + x += 3; + y -= 3; + //draw back rectangle as 4 lines so front rectangle doesn't show back rectangle through it + g2d.drawLine(x, y, x, y + 2); + g2d.drawLine(x, y, x + width, y); + x += width; + g2d.drawLine(x, y, x, y + height); + y += height; + g2d.drawLine(x - 2, y, x, y); + } + else { //otherwise just draw 1 rectangle if icon to maximize window + g2d.drawRect(x, y, width, height); + } + } + } + + public class CloseButton extends TitleBarButton { + private CloseButton() { + setToolTipText("Close"); + } + @Override + protected void onClick() { + WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev); + } + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + int thickness = 2; + int offset = 7; + int x1 = offset; + int y1 = offset; + int x2 = getWidth() - offset - 1; + int y2 = getHeight() - offset - 1; + + Graphics2D g2d = (Graphics2D) g; + skin.setGraphicsColor(g2d, foreColor); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setStroke(new BasicStroke(thickness)); + g2d.drawLine(x1, y1, x2, y2); + g2d.drawLine(x2, y1, x1, y2); + } + } +} diff --git a/src/main/java/forge/view/FView.java b/src/main/java/forge/view/FView.java index cf04314f569..4dea9294552 100644 --- a/src/main/java/forge/view/FView.java +++ b/src/main/java/forge/view/FView.java @@ -56,7 +56,9 @@ import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.JComponentSkin; import forge.gui.toolbox.FSkin.SkinCursor; import forge.model.BuildInfo; +import forge.properties.ForgePreferences; import forge.properties.NewConstants; +import forge.properties.ForgePreferences.FPref; /** */ public enum FView { @@ -65,6 +67,7 @@ public enum FView { /** */ public static final Integer TARGETING_LAYER = JLayeredPane.MODAL_LAYER - 1; + private final List allCells = new ArrayList(); private SplashFrame frmSplash; @@ -75,13 +78,15 @@ public enum FView { private final FFrame frmDocument = new FFrame(); // A layered pane is the frame's viewport, allowing overlay effects. private final DocumentPane lpnDocument = new DocumentPane(); + // The status bar to display at the bottom of the frame + private FNavigationBar navigationBar; // The content panel is placed in the layered pane. private final JPanel pnlContent = new JPanel(); - // The status bar to display at the bottom of the frame - private FStatusBar statusBar; // An insets panel neatly maintains a space from the edges of the window and // whatever layout is happening, without having to explicitly define a margin each time. private FPanel pnlInsets; + // The status bar to display at the bottom of the frame + private FStatusBar statusBar; // Preview panel is what is shown when a drag cell is being moved around private final JPanel pnlPreview = new PreviewPanel(); // Tab overflow is for the +X display for extra tabs. @@ -89,29 +94,35 @@ public enum FView { private FView() { frmSplash = new SplashFrame(); + frmDocument.setTitle("Forge: " + BuildInfo.getVersionString()); } /** */ public void initialize() { - // Insets panel has background image / texture, which - // must be instantiated after the skin is loaded. + final ForgePreferences prefs = Singletons.getModel().getPreferences(); + + // pnlInsets, navigationBar, and statusBar are skinned components + // which must be instantiated after the skin is loaded. pnlInsets = new FPanel(new BorderLayout()); pnlInsets.setBorderToggle(false); + navigationBar = new FNavigationBar(frmDocument); + statusBar = new FStatusBar(frmDocument, !prefs.getPrefBoolean(FPref.UI_HIDE_STATUS_BAR)); // Frame styling - frmDocument.initialize(); + frmDocument.initialize(navigationBar, !prefs.getPrefBoolean(FPref.UI_HIDE_TITLE_BAR)); frmDocument.setMinimumSize(new Dimension(800, 600)); frmDocument.setLocationRelativeTo(null); frmDocument.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); FSkin.get(frmDocument).setIconImage(FSkin.getIcon(FSkin.InterfaceIcons.ICO_FAVICON)); - frmDocument.setTitle("Forge: " + BuildInfo.getVersionString()); // Frame components - frmDocument.getInnerPane().setContentPane(lpnDocument); + frmDocument.setContentPane(lpnDocument); lpnDocument.add(pnlInsets, (Integer) 1); + lpnDocument.add(statusBar, (Integer) 1); //should always appear below pnlInsets, so put at same level FAbsolutePositioner.SINGLETON_INSTANCE.initialize(lpnDocument, (Integer) 2); lpnDocument.add(pnlPreview, (Integer) 3); lpnDocument.add(pnlTabOverflow, (Integer) 4); + lpnDocument.add(navigationBar, (Integer) 5); //ensure this appears over all other non-overlay layers lpnDocument.add(FOverlay.SINGLETON_INSTANCE.getPanel(), JLayeredPane.MODAL_LAYER); // Note: when adding new panels here, keep in mind that the layered pane // has a null layout, so new components will be W0 x H0 pixels - gotcha! @@ -128,11 +139,6 @@ public enum FView { pnlContent.setOpaque(false); pnlContent.setLayout(null); - // Status bar has foreground/background color which - // must be instantiated after the skin is loaded. - statusBar = new FStatusBar(frmDocument); - lpnDocument.add(statusBar, (Integer) 1); - FSkin.get(FOverlay.SINGLETON_INSTANCE.getPanel()).setBackground(FSkin.getColor(FSkin.Colors.CLR_OVERLAY)); // Populate all drag tab components. @@ -310,6 +316,11 @@ public enum FView { public DocumentPane getLpnDocument() { return lpnDocument; } + + /** @return {@link forge.view.FNavigationBar} */ + public FNavigationBar getNavigationBar() { + return navigationBar; + } /** @return {@link forge.gui.toolbox.FPanel} */ public FPanel getPnlInsets() {