mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[PyCharm] Jupyter (fix): Rewritten CollapsingComponent resize logic, removed subscription to IdeEventQueue. #PY-70825 Fixed
GitOrigin-RevId: 0f725da1fa4db2283d71a011cdea2afcfc9bf411
This commit is contained in:
committed by
intellij-monorepo-bot
parent
db375a8c52
commit
0a99d93456
+14
-8
@@ -1,7 +1,7 @@
|
||||
package org.jetbrains.plugins.notebooks.visualization.outputs.impl
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.editor.colors.EditorColors
|
||||
import com.intellij.openapi.editor.ex.EditorEx
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||
@@ -24,10 +24,12 @@ import javax.swing.JComponent
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.JPanel
|
||||
|
||||
internal class CollapsingComponent(internal val editor: EditorImpl,
|
||||
child: JComponent,
|
||||
internal val resizable: Boolean,
|
||||
private val collapsedTextSupplier: () -> @NlsSafe String) : JPanel(null) {
|
||||
internal class CollapsingComponent(
|
||||
internal val editor: EditorImpl,
|
||||
child: JComponent,
|
||||
internal val resizable: Boolean,
|
||||
private val collapsedTextSupplier: () -> @NlsSafe String,
|
||||
) : JPanel(null) {
|
||||
private var customHeight: Int = -1
|
||||
|
||||
private val resizeController by lazy {
|
||||
@@ -36,7 +38,13 @@ internal class CollapsingComponent(internal val editor: EditorImpl,
|
||||
customHeight = height - insets.run { top + bottom }
|
||||
}
|
||||
customHeight += dy
|
||||
setSize(width, customHeight)
|
||||
mainComponent.revalidate()
|
||||
}.apply {
|
||||
resizeStateDispatcher.addListener { state ->
|
||||
(border as? CollapsingComponentBorder)?.resized = state != ResizeController.ResizeState.NONE
|
||||
repaint()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +92,7 @@ internal class CollapsingComponent(internal val editor: EditorImpl,
|
||||
}
|
||||
|
||||
override fun remove(index: Int) {
|
||||
LOG.error("Components should not be deleted from $this", Throwable())
|
||||
thisLogger().error("Components should not be deleted from $this", Throwable())
|
||||
super.remove(index)
|
||||
}
|
||||
|
||||
@@ -203,8 +211,6 @@ internal class CollapsingComponent(internal val editor: EditorImpl,
|
||||
const val COLLAPSING_RECT_WIDTH = 22
|
||||
private const val COLLAPSING_RECT_MARGIN_Y_BOTTOM = 5
|
||||
|
||||
private val LOG by lazy { logger<CollapsingComponent>() }
|
||||
|
||||
@JvmStatic
|
||||
fun collapseRectHorizontalLeft(editor: EditorEx): Int =
|
||||
(editor.gutterComponentEx.width
|
||||
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
package org.jetbrains.plugins.notebooks.visualization.outputs.impl
|
||||
|
||||
import com.intellij.ide.IdeEventQueue
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.impl.EditorComponentImpl
|
||||
import com.intellij.ui.ComponentUtil
|
||||
import com.intellij.util.concurrency.ThreadingAssertions
|
||||
import org.jetbrains.plugins.notebooks.visualization.outputs.impl.ResizeHandlebarUpdater.Companion.ensureInstalled
|
||||
import java.awt.AWTEvent
|
||||
import java.awt.Component
|
||||
import java.awt.Container
|
||||
import java.awt.event.MouseEvent
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* A global event listener that draws a resizing handlebar below hovered cell outputs. Since cell outputs may contain non-Swing
|
||||
* components (like JCef), the usual MouseListener from Swing can't be used.
|
||||
*
|
||||
* Call [ensureInstalled] to initialize it.
|
||||
*/
|
||||
@Service
|
||||
class ResizeHandlebarUpdater private constructor() : IdeEventQueue.EventDispatcher, Disposable {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun ensureInstalled() {
|
||||
ThreadingAssertions.assertEventDispatchThread()
|
||||
service<ResizeHandlebarUpdater>()
|
||||
}
|
||||
}
|
||||
|
||||
private var currentCollapsingComponent = WeakReference<CollapsingComponent?>(null)
|
||||
|
||||
init {
|
||||
IdeEventQueue.getInstance().addDispatcher(this, this)
|
||||
}
|
||||
|
||||
override fun dispatch(e: AWTEvent): Boolean {
|
||||
if ((e.id != MouseEvent.MOUSE_MOVED && e.id != MouseEvent.MOUSE_WHEEL) || e !is MouseEvent) {
|
||||
return false
|
||||
}
|
||||
|
||||
setCurrentCollapsingComponent(getCollapsingComponentDepthFirst(e.component, e.x, e.y)?.takeIf { it.resizable })
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dispose() = Unit
|
||||
|
||||
private fun getCollapsingComponentDepthFirst(component: Component, x: Int, y: Int): CollapsingComponent? =
|
||||
when {
|
||||
component !is Container || !component.isVisible || !component.contains(x, y) -> null
|
||||
|
||||
component is CollapsingComponent -> component
|
||||
|
||||
else ->
|
||||
component.components.firstNotNullOfOrNull { child ->
|
||||
val loc = child.location
|
||||
getCollapsingComponentDepthFirst(child, x - loc.x, y - loc.y)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCurrentCollapsingComponent(new: CollapsingComponent?) {
|
||||
val old = currentCollapsingComponent.get()
|
||||
if (old != new) {
|
||||
(old?.border as? CollapsingComponentBorder)?.resized = false
|
||||
(new?.border as? CollapsingComponentBorder)?.resized = true
|
||||
|
||||
// We have overlapping elements over the CollapsingComponent - JupyterToolbar, and to draw it properly, we need to repaint the editor.
|
||||
val component = old ?: new
|
||||
ComponentUtil.getParentOfType(EditorComponentImpl::class.java, component)?.repaint()
|
||||
|
||||
currentCollapsingComponent = WeakReference(new)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -40,7 +40,7 @@ open class InlayComponent : JPanel(BorderLayout()), EditorCustomElementRenderer
|
||||
resizeController = ResizeController(
|
||||
component = this,
|
||||
editor = inlay!!.editor,
|
||||
deltaSize = this::deltaSize,
|
||||
deltaSize = ::deltaSize,
|
||||
)
|
||||
addMouseMotionListener(resizeController)
|
||||
addMouseListener(resizeController)
|
||||
|
||||
+31
-23
@@ -5,32 +5,46 @@ import com.intellij.openapi.editor.colors.EditorFontType
|
||||
import com.intellij.openapi.editor.impl.FontInfo
|
||||
import com.intellij.openapi.editor.impl.view.EditorPainter
|
||||
import com.intellij.openapi.editor.impl.view.FontLayoutService
|
||||
import com.intellij.util.EventDispatcher
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.Component
|
||||
import java.awt.Cursor
|
||||
import java.awt.Dimension
|
||||
import java.awt.Point
|
||||
import java.awt.event.MouseEvent
|
||||
import java.awt.event.MouseListener
|
||||
import java.awt.event.MouseMotionListener
|
||||
import java.util.EventListener
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.SwingUtilities
|
||||
import kotlin.math.abs
|
||||
|
||||
/** Realizes resize of InlayComponent by dragging resize icon in right bottom corner of component. */
|
||||
/** Realizes height-resize of InlayComponent by dragging resize area in the bottom of the component. */
|
||||
class ResizeController(
|
||||
private val component: Component,
|
||||
private val component: JComponent,
|
||||
private val editor: Editor,
|
||||
private val deltaSize: (dx: Int, dy: Int) -> Unit = component::swingDeltaSize,
|
||||
private val deltaSize: (dx: Int, dy: Int) -> Unit,
|
||||
) : MouseListener, MouseMotionListener {
|
||||
|
||||
fun interface ResizeStateListener : EventListener {
|
||||
fun onModeChanged(newState: ResizeState)
|
||||
}
|
||||
|
||||
private var prevPoint: Point? = null
|
||||
|
||||
private enum class ScaleMode { NONE, N /*, W, NW*/ }
|
||||
|
||||
enum class ResizeState { NONE, HOVER, RESIZING }
|
||||
|
||||
private var scaleMode = ScaleMode.NONE
|
||||
|
||||
private val nResizeCursor = Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)
|
||||
private val defaultCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)
|
||||
private var resizeState: ResizeState = ResizeState.NONE
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
resizeStateDispatcher.multicaster.onModeChanged(value)
|
||||
}
|
||||
}
|
||||
|
||||
val resizeStateDispatcher = EventDispatcher.create(ResizeStateListener::class.java)
|
||||
|
||||
private fun setCursor(cursor: Cursor) {
|
||||
if (component.cursor != cursor) {
|
||||
@@ -38,8 +52,7 @@ class ResizeController(
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseReleased(e: MouseEvent?) {
|
||||
|
||||
override fun mouseReleased(e: MouseEvent) {
|
||||
// Snapping to right margin.
|
||||
if (EditorPainter.isMarginShown(editor) && prevPoint != null) {
|
||||
|
||||
@@ -64,10 +77,10 @@ class ResizeController(
|
||||
|
||||
prevPoint = null
|
||||
scaleMode = ScaleMode.NONE
|
||||
resizeState = if (mouseInResizeArea(e)) ResizeState.HOVER else ResizeState.NONE
|
||||
}
|
||||
|
||||
override fun mousePressed(e: MouseEvent) {
|
||||
|
||||
val correctedHeight = component.height - InlayDimensions.bottomBorder
|
||||
|
||||
scaleMode = if (e.point.y > correctedHeight) {
|
||||
@@ -78,10 +91,10 @@ class ResizeController(
|
||||
}
|
||||
|
||||
prevPoint = e.locationOnScreen
|
||||
resizeState = ResizeState.RESIZING
|
||||
}
|
||||
|
||||
override fun mouseDragged(e: MouseEvent?) {
|
||||
|
||||
if (prevPoint == null) {
|
||||
return
|
||||
}
|
||||
@@ -94,31 +107,26 @@ class ResizeController(
|
||||
prevPoint = locationOnScreen
|
||||
}
|
||||
|
||||
override fun mouseMoved(e: MouseEvent) {
|
||||
private fun mouseInResizeArea(e: MouseEvent) = e.point.y > component.height - component.insets.bottom
|
||||
|
||||
override fun mouseMoved(e: MouseEvent) {
|
||||
if (scaleMode != ScaleMode.NONE) {
|
||||
return
|
||||
}
|
||||
|
||||
val correctedHeight = component.height - InlayDimensions.bottomBorder
|
||||
setCursor(if (e.point.y > correctedHeight) nResizeCursor else defaultCursor)
|
||||
val canResize = mouseInResizeArea(e)
|
||||
setCursor(if (canResize) Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) else Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR))
|
||||
resizeState = if (canResize) ResizeState.HOVER else ResizeState.NONE
|
||||
}
|
||||
|
||||
override fun mouseExited(e: MouseEvent) {
|
||||
if (scaleMode == ScaleMode.NONE) {
|
||||
setCursor(defaultCursor)
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR))
|
||||
resizeState = ResizeState.NONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(e: MouseEvent): Unit = Unit
|
||||
|
||||
override fun mouseEntered(e: MouseEvent): Unit = Unit
|
||||
}
|
||||
|
||||
private fun Component.swingDeltaSize(dx: Int, dy: Int) {
|
||||
val oldSize = size
|
||||
size = Dimension(oldSize.width + dx, oldSize.height + dy)
|
||||
preferredSize = size
|
||||
revalidate()
|
||||
repaint()
|
||||
}
|
||||
Reference in New Issue
Block a user