mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: terminal preview
This commit is contained in:
@@ -67,6 +67,8 @@ class TerminalDisplay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun paint(g: Graphics) {
|
override fun paint(g: Graphics) {
|
||||||
|
if (isShowing.not()) return
|
||||||
|
|
||||||
if (g is Graphics2D) {
|
if (g is Graphics2D) {
|
||||||
setupAntialiasing(g)
|
setupAntialiasing(g)
|
||||||
clear(g)
|
clear(g)
|
||||||
@@ -238,15 +240,27 @@ class TerminalDisplay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun drawCharacters(g: Graphics2D) {
|
private fun drawCharacters(g: Graphics2D) {
|
||||||
|
drawCharacters(
|
||||||
|
g = g,
|
||||||
|
verticalScrollOffset = terminal.getScrollingModel().getVerticalScrollOffset(),
|
||||||
|
rows = terminal.getTerminalModel().getRows(),
|
||||||
|
overflowBreak = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun drawCharacters(
|
||||||
|
g: Graphics2D,
|
||||||
|
verticalScrollOffset: Int,
|
||||||
|
rows: Int,
|
||||||
|
overflowBreak: Boolean,
|
||||||
|
) {
|
||||||
val terminalModel = terminal.getTerminalModel()
|
val terminalModel = terminal.getTerminalModel()
|
||||||
val reverseVideo = terminalModel.getData(DataKey.ReverseVideo, false)
|
val reverseVideo = terminalModel.getData(DataKey.ReverseVideo, false)
|
||||||
val rows = terminalModel.getRows()
|
|
||||||
val cols = terminalModel.getCols()
|
val cols = terminalModel.getCols()
|
||||||
val triple = Triple(Char.Space.toString(), TextStyle.Default, 1)
|
val triple = Triple(Char.Space.toString(), TextStyle.Default, 1)
|
||||||
val cursorPosition = terminal.getCursorModel().getPosition()
|
val cursorPosition = terminal.getCursorModel().getPosition()
|
||||||
val averageCharWidth = getAverageCharWidth()
|
val averageCharWidth = getAverageCharWidth()
|
||||||
val maxVerticalScrollOffset = terminal.getScrollingModel().getMaxVerticalScrollOffset()
|
val maxVerticalScrollOffset = terminal.getScrollingModel().getMaxVerticalScrollOffset()
|
||||||
val verticalScrollOffset = terminal.getScrollingModel().getVerticalScrollOffset()
|
|
||||||
val selectionModel = terminal.getSelectionModel()
|
val selectionModel = terminal.getSelectionModel()
|
||||||
val cursorStyle = terminalModel.getData(DataKey.CursorStyle)
|
val cursorStyle = terminalModel.getData(DataKey.CursorStyle)
|
||||||
val showCursor = terminalModel.getData(DataKey.ShowCursor)
|
val showCursor = terminalModel.getData(DataKey.ShowCursor)
|
||||||
@@ -255,11 +269,13 @@ class TerminalDisplay(
|
|||||||
val blink = terminalBlink.blink
|
val blink = terminalBlink.blink
|
||||||
val cursorBlink = terminalBlink.cursorBlink
|
val cursorBlink = terminalBlink.cursorBlink
|
||||||
val hasFocus = terminalModel.getData(TerminalPanel.Focused, false)
|
val hasFocus = terminalModel.getData(TerminalPanel.Focused, false)
|
||||||
|
val lineCount = terminal.getDocument().getLineCount()
|
||||||
|
|
||||||
for (i in 1..rows) {
|
for (i in 1..rows) {
|
||||||
var xOffset = 0
|
var xOffset = 0
|
||||||
val row = verticalScrollOffset + i - 1
|
val row = verticalScrollOffset + i - 1
|
||||||
|
// 超出总行数则熔断,避免扩容情况出现
|
||||||
|
if (overflowBreak && row >= lineCount) break
|
||||||
val characters = smartCharacters(row).iterator()
|
val characters = smartCharacters(row).iterator()
|
||||||
var j = 1
|
var j = 1
|
||||||
while (j <= cols) {
|
while (j <= cols) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package app.termora.terminal.panel
|
package app.termora.terminal.panel
|
||||||
|
|
||||||
import app.termora.Disposable
|
import app.termora.*
|
||||||
import app.termora.Disposer
|
|
||||||
import app.termora.TerminalTab
|
|
||||||
import app.termora.actions.DataProvider
|
import app.termora.actions.DataProvider
|
||||||
import app.termora.actions.DataProviderSupport
|
import app.termora.actions.DataProviderSupport
|
||||||
import app.termora.actions.DataProviders
|
import app.termora.actions.DataProviders
|
||||||
@@ -10,6 +8,7 @@ import app.termora.database.DatabaseManager
|
|||||||
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
||||||
import app.termora.terminal.*
|
import app.termora.terminal.*
|
||||||
import app.termora.terminal.panel.vw.*
|
import app.termora.terminal.panel.vw.*
|
||||||
|
import com.formdev.flatlaf.FlatClientProperties
|
||||||
import com.formdev.flatlaf.util.SystemInfo
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
import org.apache.commons.lang3.ArrayUtils
|
import org.apache.commons.lang3.ArrayUtils
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
@@ -27,11 +26,11 @@ import java.text.AttributedCharacterIterator
|
|||||||
import java.text.AttributedString
|
import java.text.AttributedString
|
||||||
import java.text.BreakIterator
|
import java.text.BreakIterator
|
||||||
import java.text.CharacterIterator
|
import java.text.CharacterIterator
|
||||||
import javax.swing.JLayeredPane
|
import javax.swing.*
|
||||||
import javax.swing.JPanel
|
|
||||||
import javax.swing.SwingUtilities
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.floor
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
@@ -47,6 +46,17 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
val FocusMode = DataKey(Boolean::class)
|
val FocusMode = DataKey(Boolean::class)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内边距
|
||||||
|
*/
|
||||||
|
var padding = Insets(4, 4, 4, 4)
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
repaintImmediate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val disposable = Disposer.newDisposable()
|
||||||
|
private val myOwner get() = SwingUtilities.getWindowAncestor(this)
|
||||||
private val properties get() = DatabaseManager.getInstance().properties
|
private val properties get() = DatabaseManager.getInstance().properties
|
||||||
private val terminalBlink = TerminalBlink(terminal)
|
private val terminalBlink = TerminalBlink(terminal)
|
||||||
private val terminalFindPanel = TerminalFindPanel(this, terminal)
|
private val terminalFindPanel = TerminalFindPanel(this, terminal)
|
||||||
@@ -54,6 +64,7 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
private val terminalDisplay = TerminalDisplay(this, terminal, terminalBlink)
|
private val terminalDisplay = TerminalDisplay(this, terminal, terminalBlink)
|
||||||
private val layeredPane = TerminalLayeredPane()
|
private val layeredPane = TerminalLayeredPane()
|
||||||
private var visualWindows = emptyArray<VisualWindow>()
|
private var visualWindows = emptyArray<VisualWindow>()
|
||||||
|
private val terminalPreviewDialog = TerminalPreviewDialog()
|
||||||
|
|
||||||
val scrollBar = TerminalScrollBar(this, terminalFindPanel, terminal)
|
val scrollBar = TerminalScrollBar(this, terminalFindPanel, terminal)
|
||||||
var enableFloatingToolbar = true
|
var enableFloatingToolbar = true
|
||||||
@@ -95,14 +106,6 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
*/
|
*/
|
||||||
var resizeToast = true
|
var resizeToast = true
|
||||||
|
|
||||||
/**
|
|
||||||
* 内边距
|
|
||||||
*/
|
|
||||||
var padding = Insets(4, 4, 4, 4)
|
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
repaintImmediate()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toast 总开关
|
* Toast 总开关
|
||||||
@@ -166,6 +169,7 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
override fun focusLost(e: FocusEvent) {
|
override fun focusLost(e: FocusEvent) {
|
||||||
terminal.getTerminalModel().setData(Focused, false)
|
terminal.getTerminalModel().setData(Focused, false)
|
||||||
repaintImmediate()
|
repaintImmediate()
|
||||||
|
hidePreview()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun focusGained(e: FocusEvent) {
|
override fun focusGained(e: FocusEvent) {
|
||||||
@@ -197,7 +201,11 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
// 滚动相关
|
// 滚动相关
|
||||||
this.addMouseWheelListener(object : MouseWheelListener {
|
this.addMouseWheelListener(object : MouseWheelListener {
|
||||||
override fun mouseWheelMoved(e: MouseWheelEvent) {
|
override fun mouseWheelMoved(e: MouseWheelEvent) {
|
||||||
if (!terminal.getScrollingModel().canVerticalScroll()) {
|
if (terminal.getScrollingModel().canVerticalScroll().not()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isShowingPreview()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +244,7 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
// 监听悬浮工具栏变化,然后重新渲染
|
// 监听悬浮工具栏变化,然后重新渲染
|
||||||
floatingToolbar.addPropertyChangeListener { repaintImmediate() }
|
floatingToolbar.addPropertyChangeListener { repaintImmediate() }
|
||||||
|
|
||||||
|
Disposer.register(this, disposable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableDropTarget() {
|
private fun enableDropTarget() {
|
||||||
@@ -416,6 +425,7 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
|
terminalPreviewDialog.dispose()
|
||||||
Disposer.dispose(terminalBlink)
|
Disposer.dispose(terminalBlink)
|
||||||
Disposer.dispose(floatingToolbar)
|
Disposer.dispose(floatingToolbar)
|
||||||
}
|
}
|
||||||
@@ -494,6 +504,64 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
super.paint(g)
|
super.paint(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun showPreview(location: Point) {
|
||||||
|
if (terminal.getScrollingModel().canVerticalScroll().not()) return
|
||||||
|
|
||||||
|
val lineHeight = terminalDisplay.getLineHeight()
|
||||||
|
val size = Dimension(
|
||||||
|
terminalDisplay.width + min((terminalDisplay.width * 0.1).toInt(), 50) + (padding.left + padding.right),
|
||||||
|
lineHeight * 10 + padding.top + padding.bottom * if (SystemInfo.isWindows_11_orLater) 2 else 1
|
||||||
|
)
|
||||||
|
val myLocation = Point(
|
||||||
|
scrollBar.locationOnScreen.x - (scrollBar.width / 2) - size.width,
|
||||||
|
location.y - lineHeight * 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// 如果超过了滚动条位置,那么使用最安全的大小
|
||||||
|
if (abs(myLocation.x) + size.width > scrollBar.locationOnScreen.x) {
|
||||||
|
size.width = terminalDisplay.width
|
||||||
|
myLocation.x = scrollBar.locationOnScreen.x - (scrollBar.width / 2) - size.width
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果超出了屏幕底部边界,那么修改弹窗位置
|
||||||
|
val rectangle = getUsableDeviceBounds(terminalPreviewDialog.graphicsConfiguration)
|
||||||
|
if (abs(myLocation.y) + size.height > rectangle.y + rectangle.height) {
|
||||||
|
myLocation.y = location.y + lineHeight * 2 - size.height
|
||||||
|
}
|
||||||
|
|
||||||
|
val point = Point(location)
|
||||||
|
SwingUtilities.convertPointFromScreen(point, scrollBar)
|
||||||
|
val scrollRatio = 1.0 * point.y / scrollBar.height
|
||||||
|
val count = max(terminal.getDocument().getLineCount(), terminal.getTerminalModel().getRows())
|
||||||
|
val totalHeight = count * lineHeight
|
||||||
|
val scrollTop = scrollRatio * totalHeight
|
||||||
|
val rowIndex = floor(scrollTop / lineHeight).toInt()
|
||||||
|
|
||||||
|
terminalPreviewDialog.row = rowIndex
|
||||||
|
terminalPreviewDialog.size = size
|
||||||
|
terminalPreviewDialog.location = myLocation
|
||||||
|
terminalPreviewDialog.isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUsableDeviceBounds(gc: GraphicsConfiguration): Rectangle {
|
||||||
|
val bounds = gc.bounds
|
||||||
|
val insets = Toolkit.getDefaultToolkit().getScreenInsets(gc)
|
||||||
|
|
||||||
|
bounds.x += insets.left
|
||||||
|
bounds.y += insets.top
|
||||||
|
bounds.width -= (insets.left + insets.right)
|
||||||
|
bounds.height -= (insets.top + insets.bottom)
|
||||||
|
|
||||||
|
return bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun hidePreview() {
|
||||||
|
terminalPreviewDialog.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun isShowingPreview() = terminalPreviewDialog.isVisible
|
||||||
|
|
||||||
private inner class TerminalLayeredPane : JLayeredPane() {
|
private inner class TerminalLayeredPane : JLayeredPane() {
|
||||||
override fun doLayout() {
|
override fun doLayout() {
|
||||||
val averageCharWidth = getAverageCharWidth()
|
val averageCharWidth = getAverageCharWidth()
|
||||||
@@ -556,6 +624,82 @@ class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val w
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class TerminalPreviewDialog : JDialog() {
|
||||||
|
|
||||||
|
private val terminalPreviewPanel = TerminalPreviewPanel()
|
||||||
|
var row
|
||||||
|
get() = terminalPreviewPanel.row
|
||||||
|
set(value) {
|
||||||
|
terminalPreviewPanel.row = value
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
initView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(b: Boolean) {
|
||||||
|
if (b) terminalPreviewPanel.repaint()
|
||||||
|
super.setVisible(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
isAlwaysOnTop = true
|
||||||
|
focusableWindowState = false
|
||||||
|
defaultCloseOperation = DISPOSE_ON_CLOSE
|
||||||
|
|
||||||
|
if (SystemInfo.isMacOS) {
|
||||||
|
rootPane.putClientProperty("apple.awt.windowTitleVisible", false)
|
||||||
|
rootPane.putClientProperty("apple.awt.fullWindowContent", true)
|
||||||
|
rootPane.putClientProperty("apple.awt.transparentTitleBar", true)
|
||||||
|
} else {
|
||||||
|
rootPane.putClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT, true)
|
||||||
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_HEIGHT, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val panel = JPanel(BorderLayout())
|
||||||
|
panel.border = BorderFactory.createEmptyBorder(
|
||||||
|
padding.top, padding.left,
|
||||||
|
padding.bottom, padding.right
|
||||||
|
)
|
||||||
|
panel.add(terminalPreviewPanel, BorderLayout.CENTER)
|
||||||
|
rootPane.contentPane = panel
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addNotify() {
|
||||||
|
super.addNotify()
|
||||||
|
if (SystemInfo.isMacOS) {
|
||||||
|
NativeMacLibrary.setControlsVisible(this, false)
|
||||||
|
} else {
|
||||||
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY, false)
|
||||||
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE, false)
|
||||||
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_CLOSE, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class TerminalPreviewPanel : JComponent() {
|
||||||
|
var row = 0
|
||||||
|
|
||||||
|
private val lineCount get() = terminal.getDocument().getLineCount()
|
||||||
|
private val rows = 10
|
||||||
|
override fun paint(g: Graphics) {
|
||||||
|
if (g !is Graphics2D) return
|
||||||
|
|
||||||
|
|
||||||
|
var row = this.row
|
||||||
|
if (row + rows > lineCount) row = row - (row + rows - lineCount)
|
||||||
|
|
||||||
|
g.save()
|
||||||
|
setupAntialiasing(g)
|
||||||
|
terminalDisplay.drawCharacters(g, verticalScrollOffset = max(0, row), rows = rows, overflowBreak = true)
|
||||||
|
g.restore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
|
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
|
||||||
if (dataKey == DataProviders.TerminalTab) {
|
if (dataKey == DataProviders.TerminalTab) {
|
||||||
|
|||||||
@@ -1,16 +1,26 @@
|
|||||||
package app.termora.terminal.panel
|
package app.termora.terminal.panel
|
||||||
|
|
||||||
|
import app.termora.swingCoroutineScope
|
||||||
import app.termora.terminal.Terminal
|
import app.termora.terminal.Terminal
|
||||||
import app.termora.terminal.TerminalColor
|
import app.termora.terminal.TerminalColor
|
||||||
import com.formdev.flatlaf.ui.FlatScrollBarUI
|
import com.formdev.flatlaf.ui.FlatScrollBarUI
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.swing.Swing
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Graphics
|
import java.awt.Graphics
|
||||||
import java.awt.Rectangle
|
import java.awt.Rectangle
|
||||||
|
import java.awt.event.MouseAdapter
|
||||||
|
import java.awt.event.MouseEvent
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
import javax.swing.JScrollBar
|
import javax.swing.JScrollBar
|
||||||
|
import javax.swing.SwingUtilities
|
||||||
import javax.swing.plaf.ScrollBarUI
|
import javax.swing.plaf.ScrollBarUI
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
class TerminalScrollBar(
|
class TerminalScrollBar(
|
||||||
private val terminalPanel: TerminalPanel,
|
private val terminalPanel: TerminalPanel,
|
||||||
@@ -19,15 +29,24 @@ class TerminalScrollBar(
|
|||||||
) : JScrollBar() {
|
) : JScrollBar() {
|
||||||
private val colorPalette get() = terminal.getTerminalModel().getColorPalette()
|
private val colorPalette get() = terminal.getTerminalModel().getColorPalette()
|
||||||
private val myUI = MyScrollBarUI()
|
private val myUI = MyScrollBarUI()
|
||||||
|
private val owner get() = SwingUtilities.getWindowAncestor(this)
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setUI(myUI)
|
setUI(myUI)
|
||||||
|
initEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setUI(ui: ScrollBarUI) {
|
override fun setUI(ui: ScrollBarUI) {
|
||||||
super.setUI(myUI)
|
super.setUI(myUI)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initEvents() {
|
||||||
|
val previewMouseAdapter = PreviewMouseAdapter()
|
||||||
|
addMouseMotionListener(previewMouseAdapter)
|
||||||
|
addMouseListener(previewMouseAdapter)
|
||||||
|
}
|
||||||
|
|
||||||
private fun drawFindMap(g: Graphics, trackBounds: Rectangle) {
|
private fun drawFindMap(g: Graphics, trackBounds: Rectangle) {
|
||||||
if (!terminalPanel.findMap) return
|
if (!terminalPanel.findMap) return
|
||||||
val kinds = terminalFindPanel.kinds
|
val kinds = terminalFindPanel.kinds
|
||||||
@@ -53,13 +72,54 @@ class TerminalScrollBar(
|
|||||||
val y = max(ceil(trackBounds.height * n).toInt() - lineHeight, 0)
|
val y = max(ceil(trackBounds.height * n).toInt() - lineHeight, 0)
|
||||||
g.fillRect(trackBounds.width - averageCharWidth, y, averageCharWidth, lineHeight)
|
g.fillRect(trackBounds.width - averageCharWidth, y, averageCharWidth, lineHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private inner class MyScrollBarUI : FlatScrollBarUI() {
|
private inner class MyScrollBarUI : FlatScrollBarUI() {
|
||||||
override fun paintTrack(g: Graphics, c: JComponent, trackBounds: Rectangle) {
|
override fun paintTrack(g: Graphics, c: JComponent, trackBounds: Rectangle) {
|
||||||
super.paintTrack(g, c, trackBounds)
|
super.paintTrack(g, c, trackBounds)
|
||||||
drawFindMap(g, trackBounds)
|
drawFindMap(g, trackBounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override fun getThumbBounds(): Rectangle {
|
||||||
|
return super.getThumbBounds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class PreviewMouseAdapter : MouseAdapter() {
|
||||||
|
private var job: Job? = null
|
||||||
|
|
||||||
|
override fun mouseMoved(e: MouseEvent) {
|
||||||
|
if (terminal.getScrollingModel().canVerticalScroll().not()) {
|
||||||
|
mouseExited(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myUI.thumbBounds.contains(e.point)) {
|
||||||
|
mouseExited(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terminalPanel.isShowingPreview()) {
|
||||||
|
doMouseMoved(e)
|
||||||
|
} else {
|
||||||
|
job?.cancel()
|
||||||
|
job = swingCoroutineScope.launch(Dispatchers.Swing) {
|
||||||
|
delay(250.milliseconds)
|
||||||
|
doMouseMoved(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doMouseMoved(e: MouseEvent) {
|
||||||
|
if (owner.isFocused.not()) return
|
||||||
|
terminalPanel.showPreview(e.locationOnScreen)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseExited(e: MouseEvent) {
|
||||||
|
job?.cancel()
|
||||||
|
terminalPanel.hidePreview()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user