Adds splash screen (#29)
* clock manager: wrap panel to run on swing thread * Add splash screen to Runelite Although RuneLite is still fast at loading, it's more user friendly for at least something to pop up before the client. There is also an option (-no-splash) to disable the splash screen. This uses psikoi's design. * splash screen/client ui: don't set up theme twice Setting up the look and feel of RuneLite shouldn't happen twice, so check to see if it has already been set up before setting up the look and feel.
This commit is contained in:
@@ -61,6 +61,7 @@ import net.runelite.client.plugins.PluginManager;
|
||||
import net.runelite.client.rs.ClientUpdateCheckMode;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.DrawManager;
|
||||
import net.runelite.client.ui.RuneLiteSplashScreen;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||
import net.runelite.client.ui.overlay.WidgetOverlay;
|
||||
@@ -79,8 +80,10 @@ public class RuneLite
|
||||
public static final File PROFILES_DIR = new File(RUNELITE_DIR, "profiles");
|
||||
public static final File PLUGIN_DIR = new File(RUNELITE_DIR, "plugins");
|
||||
public static final File SCREENSHOT_DIR = new File(RUNELITE_DIR, "screenshots");
|
||||
private static final RuneLiteSplashScreen splashScreen = new RuneLiteSplashScreen();
|
||||
|
||||
@Getter
|
||||
|
||||
@Getter
|
||||
private static Injector injector;
|
||||
|
||||
@Inject
|
||||
@@ -160,6 +163,7 @@ public class RuneLite
|
||||
final OptionParser parser = new OptionParser();
|
||||
parser.accepts("developer-mode", "Enable developer tools");
|
||||
parser.accepts("debug", "Show extra debugging output");
|
||||
parser.accepts("no-splash", "Do not show the splash screen");
|
||||
|
||||
final ArgumentAcceptingOptionSpec<ClientUpdateCheckMode> updateMode = parser
|
||||
.accepts("rs", "Select client type")
|
||||
@@ -213,6 +217,14 @@ public class RuneLite
|
||||
}
|
||||
});
|
||||
|
||||
if (!options.has("no-splash"))
|
||||
{
|
||||
splashScreen.open(4);
|
||||
}
|
||||
|
||||
// The submessage is shown in case the connection is slow
|
||||
splashScreen.setMessage("Loading client", "And checking for updates...");
|
||||
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
injector = Guice.createInjector(new RuneLiteModule(
|
||||
@@ -239,6 +251,7 @@ public class RuneLite
|
||||
}
|
||||
|
||||
// Load user configuration
|
||||
splashScreen.setMessage("Loading configuration");
|
||||
configManager.load();
|
||||
|
||||
// Load the session, including saved configuration
|
||||
@@ -252,6 +265,7 @@ public class RuneLite
|
||||
|
||||
// Load the plugins, but does not start them yet.
|
||||
// This will initialize configuration
|
||||
splashScreen.setMessage("Loading plugins and patches", "Starting session...");
|
||||
pluginManager.loadCorePlugins();
|
||||
|
||||
// Plugins have provided their config, so set default config
|
||||
@@ -261,9 +275,15 @@ public class RuneLite
|
||||
// Start client session
|
||||
clientSessionManager.start();
|
||||
|
||||
// Load the session, including saved configuration
|
||||
splashScreen.setMessage("Loading interface");
|
||||
|
||||
// Initialize UI
|
||||
clientUI.open(this);
|
||||
|
||||
// Close the splash screen
|
||||
splashScreen.close();
|
||||
|
||||
// Initialize Discord service
|
||||
discordService.init();
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.timetracking.clocks;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.inject.Singleton;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@@ -34,11 +35,13 @@ import javax.inject.Inject;
|
||||
import javax.swing.SwingUtilities;
|
||||
import joptsimple.internal.Strings;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ClockManager
|
||||
{
|
||||
@Inject
|
||||
@@ -57,7 +60,19 @@ public class ClockManager
|
||||
private final List<Stopwatch> stopwatches = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private ClockTabPanel clockTabPanel = new ClockTabPanel(this);
|
||||
private ClockTabPanel clockTabPanel;
|
||||
|
||||
ClockManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
SwingUtilities.invokeAndWait(() -> clockTabPanel = new ClockTabPanel(this));
|
||||
}
|
||||
catch (InterruptedException | InvocationTargetException e)
|
||||
{
|
||||
log.error("Error constructing ClockManager", e);
|
||||
}
|
||||
}
|
||||
|
||||
void addTimer()
|
||||
{
|
||||
|
||||
@@ -83,7 +83,6 @@ import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.input.MouseAdapter;
|
||||
import net.runelite.client.input.MouseListener;
|
||||
import net.runelite.client.input.MouseManager;
|
||||
import net.runelite.client.ui.skin.SubstanceRuneLiteLookAndFeel;
|
||||
import net.runelite.client.util.HotkeyListener;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.OSType;
|
||||
@@ -300,14 +299,7 @@ public class ClientUI
|
||||
{
|
||||
SwingUtilities.invokeAndWait(() ->
|
||||
{
|
||||
// Set some sensible swing defaults
|
||||
SwingUtil.setupDefaults();
|
||||
|
||||
// Use substance look and feel
|
||||
SwingUtil.setTheme(new SubstanceRuneLiteLookAndFeel());
|
||||
|
||||
// Use custom UI font
|
||||
SwingUtil.setFont(FontManager.getRunescapeFont());
|
||||
SwingUtil.setupRuneLiteLookAndFeel();
|
||||
|
||||
// Create main window
|
||||
frame = new ContainableFrame();
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Jeremy Plsek <github.com/jplsek>
|
||||
* 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.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Singleton;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.RuneLiteProperties;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
|
||||
/**
|
||||
* This is a custom Splash Screen and does not use Java's SplashScreen class. This has helper methods to update the
|
||||
* status while loading RuneLite. All public methods run non-blocking passed to the swing thread.
|
||||
*/
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class RuneLiteSplashScreen
|
||||
{
|
||||
private RuneLiteProperties runeLiteProperties = new RuneLiteProperties();
|
||||
|
||||
private JFrame frame;
|
||||
private JLabel messageLabel;
|
||||
private JLabel subMessageLabel;
|
||||
private JProgressBar progressBar;
|
||||
|
||||
private int currentStep;
|
||||
|
||||
/**
|
||||
* This is not done in the constructor in order to avoid processing in case the user chooses to not load
|
||||
* the splash screen.
|
||||
* @param estimatedSteps steps until completion, used for the progress bar
|
||||
*/
|
||||
private void initLayout(final int estimatedSteps)
|
||||
{
|
||||
SwingUtil.setupRuneLiteLookAndFeel();
|
||||
|
||||
// init fields with updated swing look and feel
|
||||
frame = new JFrame("RuneLitePlus Loading");
|
||||
messageLabel = new JLabel("Loading...");
|
||||
subMessageLabel = new JLabel();
|
||||
progressBar = new JProgressBar(0, estimatedSteps);
|
||||
|
||||
// frame setup
|
||||
frame.setSize(220, 290);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setUndecorated(true);
|
||||
|
||||
// main panel setup
|
||||
final JPanel panel = new JPanel();
|
||||
// To reduce substance's colorization (tinting)
|
||||
panel.putClientProperty(SubstanceSynapse.COLORIZATION_FACTOR, 1.0);
|
||||
panel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
final GridBagLayout layout = new GridBagLayout();
|
||||
layout.columnWeights = new double[]{1};
|
||||
layout.rowWeights = new double[]{1, 0, 0, 1, 0, 1};
|
||||
panel.setLayout(layout);
|
||||
|
||||
// logo
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
try
|
||||
{
|
||||
final BufferedImage logo = ImageIO.read(RuneLiteSplashScreen.class.getResourceAsStream("/runeliteplus.png"));
|
||||
frame.setIconImage(logo);
|
||||
|
||||
final BufferedImage logoTransparent = ImageIO.read(RuneLiteSplashScreen.class.getResourceAsStream("/runeliteplus_transparent.png"));
|
||||
final GridBagConstraints logoConstraints = new GridBagConstraints();
|
||||
logoConstraints.anchor = GridBagConstraints.SOUTH;
|
||||
panel.add(new JLabel(new ImageIcon(logoTransparent.getScaledInstance(96, 96, Image.SCALE_SMOOTH))), logoConstraints);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Error loading logo", e);
|
||||
}
|
||||
}
|
||||
|
||||
// runelite title
|
||||
final JLabel title = new JLabel("RuneLitePlus");
|
||||
final GridBagConstraints titleConstraints = new GridBagConstraints();
|
||||
titleConstraints.gridy = 1;
|
||||
panel.add(title, titleConstraints);
|
||||
|
||||
// version
|
||||
final JLabel version = new JLabel("Version " + runeLiteProperties.getVersion());
|
||||
version.setFont(FontManager.getRunescapeSmallFont());
|
||||
version.setForeground(version.getForeground().darker());
|
||||
final GridBagConstraints versionConstraints = new GridBagConstraints();
|
||||
versionConstraints.gridy = 2;
|
||||
panel.add(version, versionConstraints);
|
||||
|
||||
// progressbar
|
||||
final GridBagConstraints progressConstraints = new GridBagConstraints();
|
||||
progressConstraints.insets = new Insets(0, 30, 5, 30);
|
||||
progressConstraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
progressConstraints.anchor = GridBagConstraints.SOUTH;
|
||||
progressConstraints.gridy = 3;
|
||||
panel.add(progressBar, progressConstraints);
|
||||
|
||||
// main message
|
||||
messageLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
final GridBagConstraints messageConstraints = new GridBagConstraints();
|
||||
messageConstraints.gridy = 4;
|
||||
panel.add(messageLabel, messageConstraints);
|
||||
|
||||
// alternate message
|
||||
subMessageLabel.setForeground(subMessageLabel.getForeground().darker());
|
||||
subMessageLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
final GridBagConstraints altConstrains = new GridBagConstraints();
|
||||
altConstrains.anchor = GridBagConstraints.NORTH;
|
||||
altConstrains.gridy = 5;
|
||||
panel.add(subMessageLabel, altConstrains);
|
||||
|
||||
frame.setContentPane(panel);
|
||||
}
|
||||
|
||||
private boolean notActive()
|
||||
{
|
||||
return frame == null || !frame.isDisplayable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close/dispose of the splash screen
|
||||
*/
|
||||
public void close()
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
if (notActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
frame.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the splash screen to be visible.
|
||||
* @param estimatedSteps steps until completion, used for the progress bar
|
||||
*/
|
||||
public void open(final int estimatedSteps)
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
initLayout(estimatedSteps);
|
||||
frame.setVisible(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a loading message. The subMessage will also be removed.
|
||||
* @param message The main message. It will automatically append an ellipsis.
|
||||
*/
|
||||
public void setMessage(final String message)
|
||||
{
|
||||
setMessage(message, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a loading message.
|
||||
* @param message The main message. It will automatically append an ellipsis.
|
||||
* @param subMessage A separate alternate title.
|
||||
*/
|
||||
public void setMessage(final String message, final String subMessage)
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
if (notActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
messageLabel.setText(message + "...");
|
||||
subMessageLabel.setText(subMessage);
|
||||
progressBar.setValue(++currentStep);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ package net.runelite.client.util;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Image;
|
||||
@@ -52,11 +53,15 @@ import javax.swing.ToolTipManager;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.basic.BasicProgressBarUI;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.ui.components.CustomScrollBarUI;
|
||||
import net.runelite.client.ui.skin.SubstanceRuneLiteLookAndFeel;
|
||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
|
||||
/**
|
||||
@@ -65,6 +70,8 @@ import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
@Slf4j
|
||||
public class SwingUtil
|
||||
{
|
||||
private static boolean lookAndFeelIsSet = false;
|
||||
|
||||
/**
|
||||
* Sets some sensible defaults for swing.
|
||||
* IMPORTANT! Needs to be called before main frame creation
|
||||
@@ -87,6 +94,14 @@ public class SwingUtil
|
||||
UIManager.put("FormattedTextField.selectionForeground", Color.WHITE);
|
||||
UIManager.put("TextArea.selectionBackground", ColorScheme.BRAND_ORANGE_TRANSPARENT);
|
||||
UIManager.put("TextArea.selectionForeground", Color.WHITE);
|
||||
UIManager.put("ProgressBar.background", ColorScheme.BRAND_ORANGE_TRANSPARENT.darker());
|
||||
UIManager.put("ProgressBar.foreground", ColorScheme.BRAND_ORANGE);
|
||||
UIManager.put("ProgressBar.selectionBackground", ColorScheme.BRAND_ORANGE);
|
||||
UIManager.put("ProgressBar.selectionForeground", Color.BLACK);
|
||||
UIManager.put("ProgressBar.border", new EmptyBorder(0, 0, 0, 0));
|
||||
UIManager.put("ProgressBar.verticalSize", new Dimension(12, 10));
|
||||
UIManager.put("ProgressBar.horizontalSize", new Dimension(10, 12));
|
||||
UIManager.put("ProgressBarUI", BasicProgressBarUI.class.getName());
|
||||
|
||||
// Do not render shadows under popups/tooltips.
|
||||
// Fixes black boxes under popups that are above the game applet.
|
||||
@@ -277,4 +292,24 @@ public class SwingUtil
|
||||
navigationButton.setOnSelect(button::doClick);
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the RuneLite look and feel. Checks to see if the look and feel
|
||||
* was already set up before running in case the splash screen has already
|
||||
* set up the theme.
|
||||
* This must be run inside the Swing Event Dispatch thread.
|
||||
*/
|
||||
public static void setupRuneLiteLookAndFeel()
|
||||
{
|
||||
if (!lookAndFeelIsSet)
|
||||
{
|
||||
lookAndFeelIsSet = true;
|
||||
// Set some sensible swing defaults
|
||||
SwingUtil.setupDefaults();
|
||||
// Use substance look and feel
|
||||
SwingUtil.setTheme(new SubstanceRuneLiteLookAndFeel());
|
||||
// Use custom UI font
|
||||
SwingUtil.setFont(FontManager.getRunescapeFont());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user