From a106f33f9eea877228476b5f3e1a35ec73f28dc6 Mon Sep 17 00:00:00 2001 From: Igor Date: Tue, 9 Sep 2025 22:29:40 +0200 Subject: [PATCH 1/3] feat(MicrobotTopLevelConfigPanel): add new badge overlay feature - Implement new badge overlay for the Microbot Hub tab - Create text-based icons for better clarity in tab representation - Update tab management to use tooltips instead of image names --- .../ui/MicrobotTopLevelConfigPanel.java | 203 ++++++++++++++++-- .../client/plugins/microbot/ui/NEW.png | Bin 0 -> 8238 bytes .../client/plugins/microbot/ui/installed.png | Bin 0 -> 978 bytes .../client/plugins/microbot/ui/pluginhub.png | Bin 0 -> 884 bytes 4 files changed, 188 insertions(+), 15 deletions(-) create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/NEW.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/installed.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/pluginhub.png diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java index effb74108b6..f752508a5a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java @@ -6,6 +6,7 @@ import net.runelite.client.ui.components.materialtabs.MaterialTab; import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; import net.runelite.client.util.ImageUtil; +import net.runelite.client.ui.FontManager; import javax.inject.Inject; import javax.inject.Provider; @@ -13,6 +14,7 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; +import java.awt.image.BufferedImage; @Singleton public class MicrobotTopLevelConfigPanel extends PluginPanel { @@ -28,6 +30,166 @@ public class MicrobotTopLevelConfigPanel extends PluginPanel { private PluginPanel current; private boolean removeOnTabChange; + // -- BEGIN: NEW badge ( to be removed once we migrate all plugins to Hub) -- + private MaterialTab hubTab; + private JPanel glassPane; + private JLabel newBadgeOverlay; + private Timer newBadgeTimer; + + private void createNewBadgeOverlay() { + if (hubTab == null) return; + + glassPane = new JPanel() { + @Override + protected void paintChildren(Graphics g) { + super.paintChildren(g); + } + }; + glassPane.setOpaque(false); + glassPane.setLayout(null); + + newBadgeOverlay = new JLabel() { + private final BufferedImage newBadge = ImageUtil.loadImageResource(MicrobotTopLevelConfigPanel.class, "NEW.png"); + private final long startTime = System.currentTimeMillis(); + + @Override + protected void paintComponent(Graphics g) { + if (newBadge == null) { + System.out.println("DEBUG: NEW.png not found!"); + return; + } + + Graphics2D g2d = (Graphics2D) g.create(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + + double time = (System.currentTimeMillis() - startTime) % 3000; + double scale; + + if (time < 300) { + double pulsePhase = (time / 300.0) * Math.PI; + double pulseAmount = Math.sin(pulsePhase) * 0.06; + scale = 0.7 + pulseAmount; + } else { + scale = 0.7; + } + + double scaledWidth = newBadge.getWidth() * scale; + double scaledHeight = newBadge.getHeight() * scale; + + double x = (getWidth() - scaledWidth) / 2.0; + double y = (getHeight() - scaledHeight) / 2.0; + + g2d.rotate(Math.toRadians(20), getWidth() / 2.0, getHeight() / 2.0); + g2d.drawImage(newBadge, (int)x, (int)y, (int)(x + scaledWidth), (int)(y + scaledHeight), + 0, 0, newBadge.getWidth(), newBadge.getHeight(), null); + + } finally { + g2d.dispose(); + } + } + }; + + newBadgeOverlay.setOpaque(false); + newBadgeOverlay.setSize(32, 32); + glassPane.add(newBadgeOverlay); + + SwingUtilities.invokeLater(() -> { + JRootPane rootPane = SwingUtilities.getRootPane(this); + if (rootPane != null) { + rootPane.setGlassPane(glassPane); + glassPane.setVisible(true); + } + }); + + newBadgeTimer = new Timer(50, e -> { + if (hubTab != null && hubTab.isShowing() && glassPane.isVisible()) { + updateBadgePosition(); + newBadgeOverlay.setVisible(true); + newBadgeOverlay.repaint(); + } else { + newBadgeOverlay.setVisible(false); + } + }); + newBadgeTimer.start(); + } + + private void updateBadgePosition() { + if (newBadgeOverlay == null || hubTab == null || glassPane == null) return; + + try { + Point tabLocationOnScreen = hubTab.getLocationOnScreen(); + Point glassPaneLocationOnScreen = glassPane.getLocationOnScreen(); + + int x = tabLocationOnScreen.x - glassPaneLocationOnScreen.x + hubTab.getWidth() - 25; + int y = tabLocationOnScreen.y - glassPaneLocationOnScreen.y - 12; + + newBadgeOverlay.setLocation(x, y); + } catch (Exception ex) { + System.out.println("DEBUG: Error updating badge position: " + ex.getMessage()); + } + } + + private void cleanupNewBadge() { + if (newBadgeTimer != null) { + newBadgeTimer.stop(); + newBadgeTimer = null; + } + if (glassPane != null) { + glassPane.setVisible(false); + JRootPane rootPane = SwingUtilities.getRootPane(this); + if (rootPane != null) { + rootPane.setGlassPane(new JPanel()); + } + glassPane = null; + } + newBadgeOverlay = null; + System.out.println("DEBUG: Badge cleaned up"); + } + // -- END: NEW badge ( to be removed once we migrate all plugins to Hub) -- + + /** + * Creates a simple text-based icon for tabs. + * @param text {@link String} Text to display + * @param textColor {@link Color} Color of the text + * @param backgroundColor {@link Color} Background color (can be null for transparent) + * @param width Width of the icon + * @param height Height of the icon + * @return ImageIcon {@link ImageIcon} with rendered text + */ + private ImageIcon createTextIcon(String text, Color textColor, Color backgroundColor, int width, int height) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = image.createGraphics(); + + // Enable antialiasing for smoother text + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // Set background (optional, can be transparent) + if (backgroundColor != null) { + g2d.setColor(backgroundColor); + g2d.fillRect(0, 0, width, height); + } + + // Set font and text color + g2d.setFont(FontManager.getRunescapeBoldFont()); + g2d.setColor(textColor); + + // Calculate text position to center it + FontMetrics fm = g2d.getFontMetrics(); + int textWidth = fm.stringWidth(text); + int textHeight = fm.getAscent(); + + int x = (width - textWidth) / 2; + int y = (height - textHeight) / 2 + textHeight; + + g2d.drawString(text, x, y); + g2d.dispose(); + + return new ImageIcon(image); + } + @Inject MicrobotTopLevelConfigPanel( EventBus eventBus, @@ -51,46 +213,48 @@ public class MicrobotTopLevelConfigPanel extends PluginPanel { add(content, BorderLayout.CENTER); this.pluginListPanel = pluginListPanel; - pluginListPanelTab = addTab(pluginListPanel.getMuxer(), "microbot_config_icon_lg.png", "Microbot Plugins"); - addTab(microbotPluginHubPanelProvider, "plugin_hub_icon.png", "Microbot Hub"); + // Create text-based icons instead of using image files for better clarity + ImageIcon installedIcon = createTextIcon("Installed", Color.YELLOW, null, 80, 32); + ImageIcon hubIcon = createTextIcon("Plugin Hub", Color.YELLOW, null, 80, 32); + + pluginListPanelTab = addTab(pluginListPanel.getMuxer(), installedIcon, "Installed Microbot Plugins"); + hubTab = addTab(microbotPluginHubPanelProvider, hubIcon, "Microbot Hub"); tabGroup.select(pluginListPanelTab); + // Create NEW badge overlay after UI is initialized (remove after migrating all plugins to hub) + SwingUtilities.invokeLater(this::createNewBadgeOverlay); } - private MaterialTab addTab(PluginPanel panel, String image, String tooltip) { - MaterialTab mt = new MaterialTab( - new ImageIcon(ImageUtil.loadImageResource(MicrobotTopLevelConfigPanel.class, image)), - tabGroup, null); + private MaterialTab addTab(PluginPanel panel, ImageIcon icon, String tooltip) { + MaterialTab mt = new MaterialTab(icon, tabGroup, null); mt.setToolTipText(tooltip); tabGroup.addTab(mt); - content.add(image, panel.getWrappedPanel()); + content.add(tooltip, panel.getWrappedPanel()); // Use tooltip as unique key instead of image name eventBus.register(panel); mt.setOnSelectEvent(() -> { - switchTo(image, panel, false); + switchTo(tooltip, panel, false); return true; }); return mt; } - private MaterialTab addTab(Provider panelProvider, String image, String tooltip) { - MaterialTab mt = new MaterialTab( - new ImageIcon(ImageUtil.loadImageResource(MicrobotTopLevelConfigPanel.class, image)), - tabGroup, null); + private MaterialTab addTab(Provider panelProvider, ImageIcon icon, String tooltip) { + MaterialTab mt = new MaterialTab(icon, tabGroup, null); mt.setToolTipText(tooltip); tabGroup.addTab(mt); mt.setOnSelectEvent(() -> { PluginPanel panel = panelProvider.get(); - content.add(image, panel.getWrappedPanel()); + content.add(tooltip, panel.getWrappedPanel()); eventBus.register(panel); - switchTo(image, panel, true); + switchTo(tooltip, panel, true); return true; }); return mt; @@ -121,12 +285,20 @@ private void switchTo(String cardName, PluginPanel panel, boolean removeOnTabCha public void onActivate() { active = true; current.onActivate(); + // BEGIN: NEW badge readd code (remove once we migrate all plugins to hub) + if (newBadgeTimer == null || glassPane == null) { + SwingUtilities.invokeLater(this::createNewBadgeOverlay); + } + // END: NEW badge readd code (remove once we migrate all plugins to hub) } @Override public void onDeactivate() { active = false; current.onDeactivate(); + // BEGIN: NEW badge clean up code (remove once we migrate all plugins to hub) + cleanupNewBadge(); + // END: NEW badge clean up code (remove once we migrate all plugins to hub) } public void openConfigurationPanel(String name) { @@ -143,4 +315,5 @@ public void openWithFilter(String filter) { tabGroup.select(pluginListPanelTab); pluginListPanel.openWithFilter(filter); } -} \ No newline at end of file +} + diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/NEW.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/NEW.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba544548030a99933e412433163683d69e10b29 GIT binary patch literal 8238 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 L$bBpq)A#!yAA>GI literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/installed.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/installed.png new file mode 100644 index 0000000000000000000000000000000000000000..36863afec3d0408703a258f947eff27a19ebd9f4 GIT binary patch literal 978 zcmV;@11EX>4Tx04R}tkv&MmKp2MKrb<;R4(%Y~kfFM07Zq_VRV;#q(pG5I!Q|3EXws0R zxHt-~1qXi?s}3&Cx;nTDg5VE`yWphgA|-y86k5c1$8itueecWNcYx5WGS%#f0jg#h z=|o)2e3JS*_Mt`=0!T!GgAu;X18RB(Q`eQV=1djtZ)<5T#us#YCFU;~xGI$DbmXOs)zT zITlcZ3d!+<|H1Fxn#JiUHz^ngdS7h&V+;uF0jdyW16NwdUuyz$pQJZB zTI2{A+6FGJJDR))TBshHdnNb(nSZvso!K3R$!s+Z00000000mT zw*7c$nq`sNwzFCmBIOmY^;&g4Df{%}E10|4jC4L1pKrI~JoqmtCr~Pt%W2y6N+VY0 zei!FIrxJje5(oe!5J-LksWscI{ykGLd#_C@jZ9Ot+G_bV{YkkrgtZS^*YC^kJI5z+ z6^NVcN=0nKdp)&sJ`8?@xNLsIp>qaB8KN`tRzq3ETrr*zR<|l6HG-)=Q>^Mec zC&4`s9q{=SD@CTW0cT`bW3#9D#gO{DXgMyy<#dCVnV z*Gb#$_q=wyq@51wW<&cp97Mly(`=IeMnkNGACN$_arvLg=(;!`RuACjPp%ZVo19=G zT%vg$@3&m$dFSt3ZtKH4r#JFG_IuLF#CiScEX>4Tx04R}tkv&MmKp2MKrb<;R4(%Y~kfFM07Zq_VRV;#q(pG5I!Q|3EXws0R zxHt-~1qXi?s}3&Cx;nTDg5VE`yWphgA|-y86k5c1$8itueecWNcYx5WGS%#f0jg#h z=|o)2e3JS*_Mt`=0!T!GgAu;X18RB(Q`eQV=1djtZ)<5T#us#YCFU;~xGI$DbmXOs)zT zITlcZ3d!+<|H1Fxn#JiUHz^ngdS7h&V+;uF0jdyW16NwdUuyz$pQJZB zTI2{A+6FGJJDR))TPLqXrNuMoAr|| zGz{O1Q*^S*i!RRjT=~{ga3sntKnh?yhPK;wae@GGWFcav&Eph}tn! Date: Tue, 9 Sep 2025 23:07:00 +0200 Subject: [PATCH 2/3] fix(ui): prevent NEW badge flicker on initialization - Keep NEW badge overlay hidden until its position is calculated - Move initial badge positioning to SwingUtilities.invokeLater (ensure EDT layout) - Show badge only when hub tab and glass pane are visible; update position in timer loop - Properly restore previous glass pane and stop timer in cleanup - Minor cleanup to createTextIcon usage/comments --- .../ui/MicrobotTopLevelConfigPanel.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java index f752508a5a4..323683d5b8d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/ui/MicrobotTopLevelConfigPanel.java @@ -31,15 +31,20 @@ public class MicrobotTopLevelConfigPanel extends PluginPanel { private boolean removeOnTabChange; // -- BEGIN: NEW badge ( to be removed once we migrate all plugins to Hub) -- - private MaterialTab hubTab; + private final MaterialTab hubTab; private JPanel glassPane; private JLabel newBadgeOverlay; private Timer newBadgeTimer; + private Component previousGlassPane; private void createNewBadgeOverlay() { if (hubTab == null) return; glassPane = new JPanel() { + @Override + public boolean contains(int x, int y) { + return false; + } @Override protected void paintChildren(Graphics g) { super.paintChildren(g); @@ -55,7 +60,8 @@ protected void paintChildren(Graphics g) { @Override protected void paintComponent(Graphics g) { if (newBadge == null) { - System.out.println("DEBUG: NEW.png not found!"); + System.out.println("DEBUG: newBadge image is null, cannot paint"); + SwingUtilities.invokeLater(MicrobotTopLevelConfigPanel.this::cleanupNewBadge); return; } @@ -93,13 +99,18 @@ protected void paintComponent(Graphics g) { newBadgeOverlay.setOpaque(false); newBadgeOverlay.setSize(32, 32); + newBadgeOverlay.setVisible(false); glassPane.add(newBadgeOverlay); SwingUtilities.invokeLater(() -> { JRootPane rootPane = SwingUtilities.getRootPane(this); if (rootPane != null) { + if (previousGlassPane == null) { + previousGlassPane = rootPane.getGlassPane(); + } rootPane.setGlassPane(glassPane); glassPane.setVisible(true); + updateBadgePosition(); } }); @@ -119,15 +130,12 @@ private void updateBadgePosition() { if (newBadgeOverlay == null || hubTab == null || glassPane == null) return; try { - Point tabLocationOnScreen = hubTab.getLocationOnScreen(); - Point glassPaneLocationOnScreen = glassPane.getLocationOnScreen(); - - int x = tabLocationOnScreen.x - glassPaneLocationOnScreen.x + hubTab.getWidth() - 25; - int y = tabLocationOnScreen.y - glassPaneLocationOnScreen.y - 12; - + Point topRight = SwingUtilities.convertPoint(hubTab, hubTab.getWidth(), 0, glassPane); + int x = topRight.x - 25; + int y = topRight.y - 12; newBadgeOverlay.setLocation(x, y); } catch (Exception ex) { - System.out.println("DEBUG: Error updating badge position: " + ex.getMessage()); + System.out.println("DEBUG: Exception in updateBadgePosition: " + ex); } } @@ -139,13 +147,13 @@ private void cleanupNewBadge() { if (glassPane != null) { glassPane.setVisible(false); JRootPane rootPane = SwingUtilities.getRootPane(this); - if (rootPane != null) { - rootPane.setGlassPane(new JPanel()); + if (rootPane != null && previousGlassPane != null) { + rootPane.setGlassPane(previousGlassPane); + previousGlassPane = null; } glassPane = null; } newBadgeOverlay = null; - System.out.println("DEBUG: Badge cleaned up"); } // -- END: NEW badge ( to be removed once we migrate all plugins to Hub) -- @@ -316,4 +324,3 @@ public void openWithFilter(String filter) { pluginListPanel.openWithFilter(filter); } } - From ac540ad290c1364f3f0cfb38d4e1267f871cbb4c Mon Sep 17 00:00:00 2001 From: Igor Date: Tue, 9 Sep 2025 23:49:48 +0200 Subject: [PATCH 3/3] chore: remove unused images - Remove unused images from resources as normal text is being used on tabs now --- .../client/plugins/microbot/ui/installed.png | Bin 978 -> 0 bytes .../client/plugins/microbot/ui/pluginhub.png | Bin 884 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/installed.png delete mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/pluginhub.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/installed.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/ui/installed.png deleted file mode 100644 index 36863afec3d0408703a258f947eff27a19ebd9f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 978 zcmV;@11EX>4Tx04R}tkv&MmKp2MKrb<;R4(%Y~kfFM07Zq_VRV;#q(pG5I!Q|3EXws0R zxHt-~1qXi?s}3&Cx;nTDg5VE`yWphgA|-y86k5c1$8itueecWNcYx5WGS%#f0jg#h z=|o)2e3JS*_Mt`=0!T!GgAu;X18RB(Q`eQV=1djtZ)<5T#us#YCFU;~xGI$DbmXOs)zT zITlcZ3d!+<|H1Fxn#JiUHz^ngdS7h&V+;uF0jdyW16NwdUuyz$pQJZB zTI2{A+6FGJJDR))TBshHdnNb(nSZvso!K3R$!s+Z00000000mT zw*7c$nq`sNwzFCmBIOmY^;&g4Df{%}E10|4jC4L1pKrI~JoqmtCr~Pt%W2y6N+VY0 zei!FIrxJje5(oe!5J-LksWscI{ykGLd#_C@jZ9Ot+G_bV{YkkrgtZS^*YC^kJI5z+ z6^NVcN=0nKdp)&sJ`8?@xNLsIp>qaB8KN`tRzq3ETrr*zR<|l6HG-)=Q>^Mec zC&4`s9q{=SD@CTW0cT`bW3#9D#gO{DXgMyy<#dCVnV z*Gb#$_q=wyq@51wW<&cp97Mly(`=IeMnkNGACN$_arvLg=(;!`RuACjPp%ZVo19=G zT%vg$@3&m$dFSt3ZtKH4r#JFG_IuLF#CiScEX>4Tx04R}tkv&MmKp2MKrb<;R4(%Y~kfFM07Zq_VRV;#q(pG5I!Q|3EXws0R zxHt-~1qXi?s}3&Cx;nTDg5VE`yWphgA|-y86k5c1$8itueecWNcYx5WGS%#f0jg#h z=|o)2e3JS*_Mt`=0!T!GgAu;X18RB(Q`eQV=1djtZ)<5T#us#YCFU;~xGI$DbmXOs)zT zITlcZ3d!+<|H1Fxn#JiUHz^ngdS7h&V+;uF0jdyW16NwdUuyz$pQJZB zTI2{A+6FGJJDR))TPLqXrNuMoAr|| zGz{O1Q*^S*i!RRjT=~{ga3sntKnh?yhPK;wae@GGWFcav&Eph}tn!