From 1c8abf9cbaf8492d613dd56b8d93aed8efbcd71f Mon Sep 17 00:00:00 2001 From: hstyi Date: Tue, 24 Jun 2025 15:35:59 +0800 Subject: [PATCH] chore: improve badge --- plugins/bg/build.gradle.kts | 2 +- .../plugins/bg/BGGlassPaneExtension.kt | 9 ++-- .../app/termora/BadgeGlassPaneExtension.kt | 18 -------- .../kotlin/app/termora/GlassPaneExtension.kt | 8 +--- src/main/kotlin/app/termora/Graphics2D.kt | 2 + src/main/kotlin/app/termora/TermoraFrame.kt | 5 +-- .../termora/plugin/internal/badge/Badge.kt | 41 +++++++++++++++++++ .../internal/badge/BadgeGlassPaneExtension.kt | 41 +++++++++++++++++++ .../plugin/internal/badge/BadgePlugin.kt | 1 - .../internal/badge/BadgePresentation.kt | 18 ++++++++ .../terminal/panel/vw/TransferVisualWindow.kt | 11 +++-- 11 files changed, 117 insertions(+), 39 deletions(-) delete mode 100644 src/main/kotlin/app/termora/BadgeGlassPaneExtension.kt create mode 100644 src/main/kotlin/app/termora/plugin/internal/badge/Badge.kt create mode 100644 src/main/kotlin/app/termora/plugin/internal/badge/BadgeGlassPaneExtension.kt create mode 100644 src/main/kotlin/app/termora/plugin/internal/badge/BadgePresentation.kt diff --git a/plugins/bg/build.gradle.kts b/plugins/bg/build.gradle.kts index d351409..e23a321 100644 --- a/plugins/bg/build.gradle.kts +++ b/plugins/bg/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } -project.version = "0.0.3" +project.version = "0.0.4" diff --git a/plugins/bg/src/main/kotlin/app/termora/plugins/bg/BGGlassPaneExtension.kt b/plugins/bg/src/main/kotlin/app/termora/plugins/bg/BGGlassPaneExtension.kt index 871774d..800aa2f 100644 --- a/plugins/bg/src/main/kotlin/app/termora/plugins/bg/BGGlassPaneExtension.kt +++ b/plugins/bg/src/main/kotlin/app/termora/plugins/bg/BGGlassPaneExtension.kt @@ -1,6 +1,7 @@ package app.termora.plugins.bg import app.termora.GlassPaneExtension +import app.termora.WindowScope import com.formdev.flatlaf.FlatLaf import java.awt.AlphaComposite import java.awt.Graphics2D @@ -11,12 +12,9 @@ class BGGlassPaneExtension private constructor() : GlassPaneExtension { val instance = BGGlassPaneExtension() } - override fun paint( - c: JComponent, - g2d: Graphics2D - ): Boolean { + override fun paint(scope: WindowScope, c: JComponent, g2d: Graphics2D) { - val img = BackgroundManager.getInstance().getBackgroundImage() ?: return false + val img = BackgroundManager.getInstance().getBackgroundImage() ?: return g2d.composite = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, if (FlatLaf.isLafDark()) 0.2f else 0.1f @@ -24,6 +22,5 @@ class BGGlassPaneExtension private constructor() : GlassPaneExtension { g2d.drawImage(img, 0, 0, c.width, c.height, null) g2d.composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER) - return true } } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/BadgeGlassPaneExtension.kt b/src/main/kotlin/app/termora/BadgeGlassPaneExtension.kt deleted file mode 100644 index 6ee339c..0000000 --- a/src/main/kotlin/app/termora/BadgeGlassPaneExtension.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.termora - -import java.awt.Graphics2D -import javax.swing.JComponent - -class BadgeGlassPaneExtension private constructor() : GlassPaneExtension { - companion object { - val instance = BadgeGlassPaneExtension() - } - - override fun paint(c: JComponent, g2d: Graphics2D): Boolean { - return false - } - - override fun ordered(): Long { - return 0 - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/GlassPaneExtension.kt b/src/main/kotlin/app/termora/GlassPaneExtension.kt index 99a1723..cb28cd0 100644 --- a/src/main/kotlin/app/termora/GlassPaneExtension.kt +++ b/src/main/kotlin/app/termora/GlassPaneExtension.kt @@ -9,11 +9,7 @@ import javax.swing.JComponent */ interface GlassPaneExtension : Extension { - /** - * 渲染背景,如果返回 true 会立即退出。(当有多个扩展的时候,只会执行一个) - * - * @return true:渲染了背景,false:没有渲染背景 - */ - fun paint(c: JComponent, g2d: Graphics2D): Boolean + + fun paint(scope: WindowScope, c: JComponent, g2d: Graphics2D) } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/Graphics2D.kt b/src/main/kotlin/app/termora/Graphics2D.kt index 55ba024..efbf5fe 100644 --- a/src/main/kotlin/app/termora/Graphics2D.kt +++ b/src/main/kotlin/app/termora/Graphics2D.kt @@ -43,5 +43,7 @@ fun Graphics2D.restore() { fun setupAntialiasing(graphics: Graphics2D) { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) + graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON) + graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY) } diff --git a/src/main/kotlin/app/termora/TermoraFrame.kt b/src/main/kotlin/app/termora/TermoraFrame.kt index a433cf9..0f7757c 100644 --- a/src/main/kotlin/app/termora/TermoraFrame.kt +++ b/src/main/kotlin/app/termora/TermoraFrame.kt @@ -253,7 +253,7 @@ class TermoraFrame : JFrame(), DataProvider { } - private class GlassPane : JComponent() { + private inner class GlassPane : JComponent() { init { isFocusable = false @@ -266,9 +266,8 @@ class TermoraFrame : JFrame(), DataProvider { if (extensions.isNotEmpty()) { for (extension in extensions) { g2d.save() - val painted = extension.paint(this, g2d) + extension.paint(windowScope, this, g2d) g2d.restore() - if (painted) break } } } diff --git a/src/main/kotlin/app/termora/plugin/internal/badge/Badge.kt b/src/main/kotlin/app/termora/plugin/internal/badge/Badge.kt new file mode 100644 index 0000000..614a305 --- /dev/null +++ b/src/main/kotlin/app/termora/plugin/internal/badge/Badge.kt @@ -0,0 +1,41 @@ +package app.termora.plugin.internal.badge + +import app.termora.WindowScope +import java.awt.Color +import java.util.* +import javax.swing.JComponent +import javax.swing.UIManager + +class Badge private constructor() { + companion object { + fun getInstance(scope: WindowScope): Badge { + return scope.getOrCreate(Badge::class) { Badge() } + } + } + + + private val map = WeakHashMap() + + fun addBadge(component: JComponent): BadgePresentation { + val presentation = object : BadgePresentation { + override var visible: Boolean = true + override var color: Color = UIManager.getColor("Component.error.focusedBorderColor") + + override fun dispose() { + removeBadge(component) + } + } + map[component] = presentation + return presentation + } + + fun removeBadge(component: JComponent) { + map.remove(component) + } + + fun getBadges(): Map { + return map.toMap() + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/plugin/internal/badge/BadgeGlassPaneExtension.kt b/src/main/kotlin/app/termora/plugin/internal/badge/BadgeGlassPaneExtension.kt new file mode 100644 index 0000000..ef0d964 --- /dev/null +++ b/src/main/kotlin/app/termora/plugin/internal/badge/BadgeGlassPaneExtension.kt @@ -0,0 +1,41 @@ +package app.termora.plugin.internal.badge + +import app.termora.GlassPaneExtension +import app.termora.WindowScope +import app.termora.setupAntialiasing +import java.awt.Graphics2D +import javax.swing.JComponent +import javax.swing.SwingUtilities + +class BadgeGlassPaneExtension private constructor() : GlassPaneExtension { + companion object { + val instance = BadgeGlassPaneExtension() + } + + override fun paint(scope: WindowScope, c: JComponent, g2d: Graphics2D) { + val badges = Badge.getInstance(scope).getBadges() + if (badges.isEmpty()) return + + setupAntialiasing(g2d) + + for ((comp, presentation) in badges) { + if (comp.isShowing.not()) continue + if (presentation.visible.not()) continue + paintBadge(c, comp, g2d, presentation) + } + + } + + private fun paintBadge(root: JComponent, c: JComponent, g2d: Graphics2D, presentation: BadgePresentation) { + val point = c.locationOnScreen + SwingUtilities.convertPointFromScreen(point, root) + val size = 6 + g2d.color = presentation.color + g2d.fillRoundRect(c.width - size - 4 + point.x, point.y + 4, size, size, size, size) + } + + + override fun ordered(): Long { + return Long.MAX_VALUE + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/plugin/internal/badge/BadgePlugin.kt b/src/main/kotlin/app/termora/plugin/internal/badge/BadgePlugin.kt index a3c7a7b..04fb753 100644 --- a/src/main/kotlin/app/termora/plugin/internal/badge/BadgePlugin.kt +++ b/src/main/kotlin/app/termora/plugin/internal/badge/BadgePlugin.kt @@ -1,6 +1,5 @@ package app.termora.plugin.internal.badge -import app.termora.BadgeGlassPaneExtension import app.termora.GlassPaneExtension import app.termora.plugin.Extension import app.termora.plugin.InternalPlugin diff --git a/src/main/kotlin/app/termora/plugin/internal/badge/BadgePresentation.kt b/src/main/kotlin/app/termora/plugin/internal/badge/BadgePresentation.kt new file mode 100644 index 0000000..7a96aa8 --- /dev/null +++ b/src/main/kotlin/app/termora/plugin/internal/badge/BadgePresentation.kt @@ -0,0 +1,18 @@ +package app.termora.plugin.internal.badge + +import app.termora.Disposable +import java.awt.Color + +interface BadgePresentation : Disposable { + + /** + * 是否显示 + */ + var visible: Boolean + + /** + * 颜色 + */ + var color: Color + +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/TransferVisualWindow.kt b/src/main/kotlin/app/termora/terminal/panel/vw/TransferVisualWindow.kt index 2d15322..0969800 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/TransferVisualWindow.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/TransferVisualWindow.kt @@ -4,6 +4,7 @@ import app.termora.* import app.termora.actions.AnAction import app.termora.actions.AnActionEvent import app.termora.actions.DataProviders +import app.termora.plugin.internal.badge.Badge import app.termora.plugin.internal.ssh.SSHTerminalTab import app.termora.plugin.internal.ssh.SSHTerminalTab.Companion.SSHSession import app.termora.terminal.DataKey @@ -61,8 +62,9 @@ class TransferVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindo private val disposable = Disposer.newDisposable() private val owner get() = SwingUtilities.getWindowAncestor(this) private val questionBtn = JButton(Icons.questionMark) - private val badgeIcon = BadgeIcon(Icons.download) - private val downloadBtn = JButton(badgeIcon) + private val downloadBtn = JButton(Icons.download) + private val badgePresentation = Badge.getInstance(tab.windowScope) + .addBadge(downloadBtn).apply { visible = false } init { @@ -86,6 +88,7 @@ class TransferVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindo Disposer.register(tab, this) Disposer.register(this, disposable) Disposer.register(disposable, transferManager) + Disposer.register(disposable, badgePresentation) connectingPanel.busyLabel.isBusy = true @@ -115,10 +118,10 @@ class TransferVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindo transferManager.addTransferListener(object : TransferListener { override fun onTransferCountChanged() { - val oldVisible = badgeIcon.visible + val oldVisible = badgePresentation.visible val newVisible = transferManager.getTransferCount() > 0 if (oldVisible != newVisible) { - badgeIcon.visible = newVisible + badgePresentation.visible = newVisible downloadBtn.repaint() } }