Remove the need for custom TitleToolbar component
- Extract title toolbar layout to separate component - Create new events for adding and removing title toolbar buttons - Create TitleToolbar through Guice Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
@@ -46,6 +46,7 @@ import net.runelite.client.discord.DiscordService;
|
|||||||
import net.runelite.client.menus.MenuManager;
|
import net.runelite.client.menus.MenuManager;
|
||||||
import net.runelite.client.plugins.PluginManager;
|
import net.runelite.client.plugins.PluginManager;
|
||||||
import net.runelite.client.ui.ClientUI;
|
import net.runelite.client.ui.ClientUI;
|
||||||
|
import net.runelite.client.ui.TitleToolbar;
|
||||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
@@ -93,6 +94,9 @@ public class RuneLite
|
|||||||
@Inject
|
@Inject
|
||||||
private ClientUI clientUI;
|
private ClientUI clientUI;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private TitleToolbar titleToolbar;
|
||||||
|
|
||||||
Client client;
|
Client client;
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception
|
public static void main(String[] args) throws Exception
|
||||||
@@ -176,6 +180,9 @@ public class RuneLite
|
|||||||
// Load the session, including saved configuration
|
// Load the session, including saved configuration
|
||||||
sessionManager.loadSession();
|
sessionManager.loadSession();
|
||||||
|
|
||||||
|
// Refresh title toolbar
|
||||||
|
titleToolbar.refresh();
|
||||||
|
|
||||||
// Show UI after all plugins are loaded
|
// Show UI after all plugins are loaded
|
||||||
clientUI.show();
|
clientUI.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.events;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
import net.runelite.client.ui.NavigationButton;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class TitleToolbarButtonAdded
|
||||||
|
{
|
||||||
|
private NavigationButton button;
|
||||||
|
private int index;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.events;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
import net.runelite.client.ui.NavigationButton;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class TitleToolbarButtonRemoved
|
||||||
|
{
|
||||||
|
private NavigationButton button;
|
||||||
|
private int index;
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Abex
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.ui;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.LayoutManager2;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client title toolbar component.
|
||||||
|
*/
|
||||||
|
public class ClientTitleToolbar extends JPanel
|
||||||
|
{
|
||||||
|
public static final int TITLEBAR_SIZE = 23;
|
||||||
|
private static final int ITEM_PADDING = 4;
|
||||||
|
|
||||||
|
private final Map<NavigationButton, Component> componentMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Client title toolbar.
|
||||||
|
*/
|
||||||
|
public ClientTitleToolbar()
|
||||||
|
{
|
||||||
|
// The only other layout manager that would manage it's preferred size without padding
|
||||||
|
// was the GroupLayout manager, which doesn't work with dynamic layouts like this one.
|
||||||
|
// Primarily, it would not remove components unless it was immediately repainted.
|
||||||
|
setLayout(new LayoutManager2()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void addLayoutComponent(String name, Component comp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addLayoutComponent(Component comp, Object constraints)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeLayoutComponent(Component comp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension preferredLayoutSize(Container parent)
|
||||||
|
{
|
||||||
|
int width = parent.getComponentCount() * (TITLEBAR_SIZE + ITEM_PADDING);
|
||||||
|
return new Dimension(width, TITLEBAR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension minimumLayoutSize(Container parent)
|
||||||
|
{
|
||||||
|
return preferredLayoutSize(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension maximumLayoutSize(Container parent)
|
||||||
|
{
|
||||||
|
return preferredLayoutSize(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getLayoutAlignmentX(Container target)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getLayoutAlignmentY(Container target)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateLayout(Container target)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layoutContainer(Container parent)
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
for (Component c : parent.getComponents())
|
||||||
|
{
|
||||||
|
x += ITEM_PADDING;
|
||||||
|
int height = c.getPreferredSize().height;
|
||||||
|
if (height > TITLEBAR_SIZE)
|
||||||
|
{
|
||||||
|
height = TITLEBAR_SIZE;
|
||||||
|
}
|
||||||
|
c.setBounds(x, (TITLEBAR_SIZE - height) / 2, TITLEBAR_SIZE, height);
|
||||||
|
x += TITLEBAR_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addComponent(NavigationButton button, Component c)
|
||||||
|
{
|
||||||
|
if (componentMap.put(button, c) == null)
|
||||||
|
{
|
||||||
|
add(c);
|
||||||
|
revalidate();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeComponent(NavigationButton button)
|
||||||
|
{
|
||||||
|
final Component component = componentMap.remove(button);
|
||||||
|
if (component != null)
|
||||||
|
{
|
||||||
|
remove(component);
|
||||||
|
revalidate();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,10 +63,13 @@ import net.runelite.client.config.RuneLiteConfig;
|
|||||||
import net.runelite.client.events.ClientUILoaded;
|
import net.runelite.client.events.ClientUILoaded;
|
||||||
import net.runelite.client.events.PluginToolbarButtonAdded;
|
import net.runelite.client.events.PluginToolbarButtonAdded;
|
||||||
import net.runelite.client.events.PluginToolbarButtonRemoved;
|
import net.runelite.client.events.PluginToolbarButtonRemoved;
|
||||||
|
import net.runelite.client.events.TitleToolbarButtonAdded;
|
||||||
|
import net.runelite.client.events.TitleToolbarButtonRemoved;
|
||||||
import net.runelite.client.util.OSType;
|
import net.runelite.client.util.OSType;
|
||||||
import net.runelite.client.util.OSXUtil;
|
import net.runelite.client.util.OSXUtil;
|
||||||
import net.runelite.client.util.SwingUtil;
|
import net.runelite.client.util.SwingUtil;
|
||||||
import org.pushingpixels.substance.api.skin.SubstanceGraphiteLookAndFeel;
|
import org.pushingpixels.substance.api.skin.SubstanceGraphiteLookAndFeel;
|
||||||
|
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||||
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
|
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
|
||||||
import org.pushingpixels.substance.internal.utils.SubstanceTitlePaneUtilities;
|
import org.pushingpixels.substance.internal.utils.SubstanceTitlePaneUtilities;
|
||||||
|
|
||||||
@@ -102,9 +105,6 @@ public class ClientUI
|
|||||||
@Getter
|
@Getter
|
||||||
private TrayIcon trayIcon;
|
private TrayIcon trayIcon;
|
||||||
|
|
||||||
@Getter
|
|
||||||
private TitleToolbar titleToolbar;
|
|
||||||
|
|
||||||
private final RuneLite runelite;
|
private final RuneLite runelite;
|
||||||
private final RuneLiteProperties properties;
|
private final RuneLiteProperties properties;
|
||||||
private final RuneLiteConfig config;
|
private final RuneLiteConfig config;
|
||||||
@@ -114,6 +114,7 @@ public class ClientUI
|
|||||||
private JPanel navContainer;
|
private JPanel navContainer;
|
||||||
private PluginPanel pluginPanel;
|
private PluginPanel pluginPanel;
|
||||||
private ClientPluginToolbar pluginToolbar;
|
private ClientPluginToolbar pluginToolbar;
|
||||||
|
private ClientTitleToolbar titleToolbar;
|
||||||
private JButton currentButton;
|
private JButton currentButton;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -247,6 +248,48 @@ public class ClientUI
|
|||||||
SwingUtilities.invokeLater(() -> pluginToolbar.removeComponent(event.getButton()));
|
SwingUtilities.invokeLater(() -> pluginToolbar.removeComponent(event.getButton()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onTitleToolbarButtonAdded(final TitleToolbarButtonAdded event)
|
||||||
|
{
|
||||||
|
if (!config.enableCustomChrome())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() ->
|
||||||
|
{
|
||||||
|
|
||||||
|
final int iconSize = ClientTitleToolbar.TITLEBAR_SIZE - 6;
|
||||||
|
final BufferedImage scaledImage = SwingUtil.resizeImage(event.getButton().getIcon(), iconSize, iconSize);
|
||||||
|
final JButton button = new JButton();
|
||||||
|
button.setName(event.getButton().getName());
|
||||||
|
button.setToolTipText(event.getButton().getTooltip());
|
||||||
|
button.setIcon(new ImageIcon(scaledImage));
|
||||||
|
button.setRolloverIcon(new ImageIcon(SwingUtil.createInvertedImage(scaledImage)));
|
||||||
|
button.putClientProperty(SubstanceSynapse.FLAT_LOOK, Boolean.TRUE);
|
||||||
|
button.setFocusable(false);
|
||||||
|
|
||||||
|
if (event.getButton().getOnClick() != null)
|
||||||
|
{
|
||||||
|
button.addActionListener(e -> event.getButton().getOnClick().run());
|
||||||
|
}
|
||||||
|
|
||||||
|
event.getButton().setOnSelect(() -> button.setSelected(event.getButton().isSelected()));
|
||||||
|
titleToolbar.addComponent(event.getButton(), button);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onTitleToolbarButtonRemoved(final TitleToolbarButtonRemoved event)
|
||||||
|
{
|
||||||
|
if (!config.enableCustomChrome())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> titleToolbar.removeComponent(event.getButton()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize UI.
|
* Initialize UI.
|
||||||
*
|
*
|
||||||
@@ -300,8 +343,7 @@ public class ClientUI
|
|||||||
pluginToolbar = new ClientPluginToolbar();
|
pluginToolbar = new ClientPluginToolbar();
|
||||||
container.add(pluginToolbar);
|
container.add(pluginToolbar);
|
||||||
|
|
||||||
titleToolbar = new TitleToolbar(properties);
|
titleToolbar = new ClientTitleToolbar();
|
||||||
|
|
||||||
frame.add(container);
|
frame.add(container);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -323,7 +365,7 @@ public class ClientUI
|
|||||||
{
|
{
|
||||||
frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
|
frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
|
||||||
|
|
||||||
JComponent titleBar = SubstanceCoreUtilities.getTitlePaneComponent(frame);
|
final JComponent titleBar = SubstanceCoreUtilities.getTitlePaneComponent(frame);
|
||||||
titleToolbar.putClientProperty(SubstanceTitlePaneUtilities.EXTRA_COMPONENT_KIND, SubstanceTitlePaneUtilities.ExtraComponentKind.TRAILING);
|
titleToolbar.putClientProperty(SubstanceTitlePaneUtilities.EXTRA_COMPONENT_KIND, SubstanceTitlePaneUtilities.ExtraComponentKind.TRAILING);
|
||||||
titleBar.add(titleToolbar);
|
titleBar.add(titleToolbar);
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UI navigation button.
|
* UI navigation button.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
|
@EqualsAndHashCode(of = {"name", "tooltip"})
|
||||||
public class NavigationButton
|
public class NavigationButton
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 Abex
|
* Copyright (c) 2017-2018, Adam <Adam@sigterm.info>
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -24,174 +25,78 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.ui;
|
package net.runelite.client.ui;
|
||||||
|
|
||||||
import java.awt.Component;
|
import com.google.common.eventbus.EventBus;
|
||||||
import java.awt.Container;
|
import java.util.Comparator;
|
||||||
import java.awt.Desktop;
|
import java.util.Iterator;
|
||||||
import java.awt.Dimension;
|
import java.util.TreeSet;
|
||||||
import java.awt.Image;
|
import javax.inject.Inject;
|
||||||
import java.awt.LayoutManager2;
|
import javax.inject.Singleton;
|
||||||
import java.awt.event.MouseAdapter;
|
import net.runelite.client.events.TitleToolbarButtonAdded;
|
||||||
import java.awt.event.MouseEvent;
|
import net.runelite.client.events.TitleToolbarButtonRemoved;
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import net.runelite.client.RuneLiteProperties;
|
|
||||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
|
||||||
|
|
||||||
@Slf4j
|
/**
|
||||||
public class TitleToolbar extends JPanel
|
* Title toolbar buttons holder.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class TitleToolbar
|
||||||
{
|
{
|
||||||
private static final int TITLEBAR_SIZE = 23;
|
private final EventBus eventBus;
|
||||||
private static final int ITEM_PADDING = 4;
|
private final TreeSet<NavigationButton> buttons = new TreeSet<>(Comparator.comparing(NavigationButton::getTooltip));
|
||||||
|
|
||||||
public TitleToolbar(RuneLiteProperties properties)
|
@Inject
|
||||||
|
private TitleToolbar(final EventBus eventBus)
|
||||||
{
|
{
|
||||||
// The only other layout manager that would manage it's preferred size without padding
|
this.eventBus = eventBus;
|
||||||
// was the GroupLayout manager, which doesn't work with dynamic layouts like this one.
|
}
|
||||||
// Primarily, it would not remove components unless it was immediately repainted.
|
|
||||||
setLayout(new LayoutManager2()
|
/**
|
||||||
|
* Add navigation.
|
||||||
|
*
|
||||||
|
* @param button the button
|
||||||
|
*/
|
||||||
|
public void addNavigation(final NavigationButton button)
|
||||||
|
{
|
||||||
|
if (buttons.contains(button))
|
||||||
{
|
{
|
||||||
@Override
|
return;
|
||||||
public void addLayoutComponent(String name, Component comp)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addLayoutComponent(Component comp, Object constraints)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeLayoutComponent(Component comp)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension preferredLayoutSize(Container parent)
|
|
||||||
{
|
|
||||||
int width = parent.getComponentCount() * (TITLEBAR_SIZE + ITEM_PADDING);
|
|
||||||
return new Dimension(width, TITLEBAR_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension minimumLayoutSize(Container parent)
|
|
||||||
{
|
|
||||||
return preferredLayoutSize(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension maximumLayoutSize(Container parent)
|
|
||||||
{
|
|
||||||
return preferredLayoutSize(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getLayoutAlignmentX(Container target)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getLayoutAlignmentY(Container target)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidateLayout(Container target)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void layoutContainer(Container parent)
|
|
||||||
{
|
|
||||||
int x = 0;
|
|
||||||
for (Component c : parent.getComponents())
|
|
||||||
{
|
|
||||||
x += ITEM_PADDING;
|
|
||||||
int height = c.getPreferredSize().height;
|
|
||||||
if (height > TITLEBAR_SIZE)
|
|
||||||
{
|
|
||||||
height = TITLEBAR_SIZE;
|
|
||||||
}
|
|
||||||
c.setBounds(x, (TITLEBAR_SIZE - height) / 2, TITLEBAR_SIZE, height);
|
|
||||||
x += TITLEBAR_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
BufferedImage discordIcon;
|
|
||||||
BufferedImage invertedIcon;
|
|
||||||
synchronized (ImageIO.class)
|
|
||||||
{
|
|
||||||
discordIcon = ImageIO.read(ClientUI.class.getResourceAsStream("discord.png"));
|
|
||||||
invertedIcon = ImageIO.read(ClientUI.class.getResourceAsStream("discord_inverted.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
JButton discordButton = new JButton();
|
|
||||||
discordButton.setToolTipText("Join Discord");
|
|
||||||
discordButton.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
super.mouseClicked(e);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Desktop.getDesktop().browse(new URL(properties.getDiscordInvite()).toURI());
|
|
||||||
}
|
|
||||||
catch (IOException | URISyntaxException ex)
|
|
||||||
{
|
|
||||||
log.warn("error opening browser", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addButton(discordButton, discordIcon, invertedIcon);
|
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
|
||||||
|
if (buttons.add(button))
|
||||||
{
|
{
|
||||||
log.warn("unable to load discord button", ex);
|
int index = buttons.headSet(button).size();
|
||||||
|
eventBus.post(new TitleToolbarButtonAdded(button, index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addButton(JButton button, Image iconImage, Image invertedIconImage)
|
/**
|
||||||
|
* Remove navigation.
|
||||||
|
*
|
||||||
|
* @param button the button
|
||||||
|
*/
|
||||||
|
public void removeNavigation(final NavigationButton button)
|
||||||
{
|
{
|
||||||
final int iconSize = TITLEBAR_SIZE - 6;
|
int index = buttons.headSet(button).size();
|
||||||
ImageIcon icon = new ImageIcon(iconImage.getScaledInstance(iconSize, iconSize, Image.SCALE_SMOOTH));
|
|
||||||
ImageIcon invertedIcon;
|
|
||||||
if (invertedIconImage == null)
|
|
||||||
{
|
|
||||||
invertedIcon = icon;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
invertedIcon = new ImageIcon(invertedIconImage.getScaledInstance(iconSize, iconSize, Image.SCALE_SMOOTH));
|
|
||||||
}
|
|
||||||
|
|
||||||
button.setIcon(icon);
|
if (buttons.remove(button))
|
||||||
button.setRolloverIcon(invertedIcon);
|
{
|
||||||
button.putClientProperty(SubstanceSynapse.FLAT_LOOK, Boolean.TRUE);
|
eventBus.post(new TitleToolbarButtonRemoved(button, index));
|
||||||
button.setFocusable(false);
|
}
|
||||||
|
|
||||||
add(button);
|
|
||||||
revalidate();
|
|
||||||
repaint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void remove(Component c)
|
* Refresh all buttons
|
||||||
|
*/
|
||||||
|
public void refresh()
|
||||||
{
|
{
|
||||||
super.remove(c);
|
final Iterator<NavigationButton> iterator = buttons.iterator();
|
||||||
revalidate();
|
int index = 0;
|
||||||
repaint();
|
|
||||||
|
while (iterator.hasNext())
|
||||||
|
{
|
||||||
|
final NavigationButton button = iterator.next();
|
||||||
|
eventBus.post(new TitleToolbarButtonRemoved(button, index));
|
||||||
|
eventBus.post(new TitleToolbarButtonAdded(button, index));
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user