mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[jupyter] PY-66455 heavyweight jupyter toolbar
GitOrigin-RevId: 11b9129165e643c33d3c8ff7be6390d49c3e44a5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fffb2b1459
commit
5000e32a42
+11
-4
@@ -1,8 +1,10 @@
|
||||
package org.jetbrains.plugins.notebooks.ui.jupyterToolbar
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.actionSystem.ActionGroup
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl
|
||||
import com.intellij.openapi.actionSystem.toolbarLayout.ToolbarLayoutStrategy
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.NewUiValue
|
||||
@@ -14,23 +16,27 @@ import java.awt.Cursor
|
||||
import java.awt.Graphics
|
||||
import java.awt.Graphics2D
|
||||
import javax.swing.BorderFactory
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
|
||||
/**
|
||||
* @See com.intellij.bigdatatools.visualization.inlays.components.FadingToolbar
|
||||
* PY-66455
|
||||
*/
|
||||
class JupyterToolbar(actionGroup: ActionGroup) : ActionToolbarImpl(ActionPlaces.EDITOR_INLAY, actionGroup, true) {
|
||||
class JupyterToolbar(actionGroup: ActionGroup, target: JComponent) :
|
||||
ActionToolbarImpl(ActionPlaces.EDITOR_INLAY, actionGroup, true)
|
||||
{
|
||||
init {
|
||||
val borderColor = when (NewUiValue.isEnabled()) {
|
||||
true ->JBColor.LIGHT_GRAY
|
||||
else -> JBColor.DARK_GRAY
|
||||
true -> JBColor.LIGHT_GRAY
|
||||
else -> JBColor.GRAY
|
||||
}
|
||||
|
||||
border = BorderFactory.createCompoundBorder(RoundedLineBorder(borderColor, TOOLBAR_ARC_SIZE, TOOLBAR_BORDER_THICKNESS),
|
||||
BorderFactory.createEmptyBorder(OUTER_PADDING, OUTER_PADDING, OUTER_PADDING, OUTER_PADDING))
|
||||
isOpaque = false
|
||||
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
|
||||
targetComponent = target
|
||||
setSkipWindowAdjustments(false)
|
||||
}
|
||||
|
||||
@@ -51,6 +57,7 @@ class JupyterToolbar(actionGroup: ActionGroup) : ActionToolbarImpl(ActionPlaces.
|
||||
if (!StartupUiUtil.isDarkTheme) {
|
||||
background = JBColor.WHITE
|
||||
}
|
||||
layoutStrategy = ToolbarLayoutStrategy.NOWRAP_STRATEGY
|
||||
}
|
||||
|
||||
fun getRespectiveLineNumberInEditor(editor: Editor): Int? {
|
||||
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
package org.jetbrains.plugins.notebooks.ui.jupyterToolbar
|
||||
|
||||
import com.intellij.ide.ui.customization.CustomActionsSchema
|
||||
import com.intellij.openapi.actionSystem.ActionGroup
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.ui.scale.JBUIScale
|
||||
import java.awt.Dimension
|
||||
import java.awt.MouseInfo
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.awt.event.*
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.SwingUtilities
|
||||
import javax.swing.Timer
|
||||
|
||||
class JupyterToolbarManager(
|
||||
private val editor: EditorImpl,
|
||||
private val panel: JPanel,
|
||||
private val actionGroupId: String
|
||||
) { // See PY-66455
|
||||
private var toolbar: JupyterToolbar? = null
|
||||
private var hideToolbarTimer = Timer(TOOLBAR_HIDE_DELAY) { conditionallyHideToolBar() }
|
||||
|
||||
init {
|
||||
initPanelMouseListeners()
|
||||
addPanelComponentListener()
|
||||
addEditorKeyListener()
|
||||
addEditorComponentListener()
|
||||
}
|
||||
|
||||
private fun initPanelMouseListeners() {
|
||||
val mouseAdapter = object : MouseAdapter() {
|
||||
override fun mouseEntered(e: MouseEvent) {
|
||||
hideToolbarTimer.stop()
|
||||
showToolbar()
|
||||
}
|
||||
|
||||
override fun mouseExited(e: MouseEvent) {
|
||||
hideToolbarTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
panel.addMouseListener(mouseAdapter)
|
||||
}
|
||||
|
||||
private fun addPanelComponentListener() {
|
||||
val componentListener = object : ComponentAdapter() {
|
||||
override fun componentResized(e: ComponentEvent?) {
|
||||
super.componentResized(e)
|
||||
toolbar?.let {
|
||||
it.bounds = calculateToolbarBounds(editor, panel, it.preferredSize)
|
||||
panel.revalidate()
|
||||
panel.repaint()
|
||||
}
|
||||
}
|
||||
|
||||
override fun componentMoved(e: ComponentEvent?) {
|
||||
super.componentMoved(e)
|
||||
toolbar?.let {
|
||||
it.bounds = calculateToolbarBounds(editor, panel, it.preferredSize)
|
||||
panel.revalidate()
|
||||
panel.repaint()
|
||||
}
|
||||
}
|
||||
}
|
||||
panel.addComponentListener(componentListener)
|
||||
}
|
||||
|
||||
private fun addEditorKeyListener() {
|
||||
val keyAdapter = object : KeyAdapter() {
|
||||
override fun keyTyped(e: KeyEvent) = hideToolBar()
|
||||
override fun keyPressed(e: KeyEvent) = hideToolBar()
|
||||
}
|
||||
|
||||
editor.contentComponent.addKeyListener(keyAdapter)
|
||||
}
|
||||
|
||||
private fun addEditorComponentListener() {
|
||||
editor.contentComponent.addComponentListener(object : ComponentAdapter() {
|
||||
override fun componentResized(e: ComponentEvent?) = hideToolBar()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the mouse is over the toolbar before hiding it.
|
||||
* This is necessary because mouseExited events on the panel can trigger even when the mouse
|
||||
* is over the toolbar due to its position in the Z-stack.
|
||||
* If the mouse is indeed over the toolbar, hiding is deferred to prevent an unintended disappearance,
|
||||
* acting as an additional safeguard for better user experience.
|
||||
*/
|
||||
private fun conditionallyHideToolBar() {
|
||||
toolbar?.let { tb ->
|
||||
val mousePos = MouseInfo.getPointerInfo().location
|
||||
SwingUtilities.convertPointFromScreen(mousePos, editor.contentComponent)
|
||||
|
||||
if (tb.bounds.contains(mousePos)) {
|
||||
hideToolbarTimer.restart()
|
||||
} else {
|
||||
hideToolBar() // mouse is not over the toolbar - we may hide it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hideToolBar() {
|
||||
toolbar?.let {
|
||||
editor.contentComponent.remove(it)
|
||||
editor.contentComponent.revalidate()
|
||||
editor.contentComponent.repaint()
|
||||
toolbar = null
|
||||
JupyterToolbarVisibilityManager.notifyToolbarHidden(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showToolbar() {
|
||||
if (toolbar == null) {
|
||||
val actionGroup = createActionGroup() ?: return
|
||||
toolbar = JupyterToolbar(actionGroup).apply {
|
||||
targetComponent = editor.contentComponent
|
||||
}
|
||||
}
|
||||
JupyterToolbarVisibilityManager.requestToolbarDisplay(this)
|
||||
editor.contentComponent.add(toolbar, 0)
|
||||
positionToolbar()
|
||||
}
|
||||
|
||||
private fun positionToolbar() {
|
||||
toolbar?.let { tb ->
|
||||
val bounds = calculateToolbarBounds(editor, panel, tb.preferredSize)
|
||||
tb.bounds = bounds
|
||||
}
|
||||
}
|
||||
|
||||
private fun createActionGroup(): ActionGroup? {
|
||||
return CustomActionsSchema.getInstance().getCorrectedAction(actionGroupId) as? ActionGroup
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_Y_OFFSET = JBUIScale.scale(-10)
|
||||
private const val TOOLBAR_HIDE_DELAY = 800
|
||||
|
||||
fun calculateToolbarBounds(
|
||||
editor: EditorImpl,
|
||||
panel: JPanel,
|
||||
toolbar: Dimension,
|
||||
extraYOffset: Int = 0
|
||||
) : Rectangle {
|
||||
val xOffset = (panel.width - toolbar.width) / 2
|
||||
val yOffset = DEFAULT_Y_OFFSET + extraYOffset
|
||||
|
||||
val editorComponent = editor.contentComponent
|
||||
val panelLocationInEditor = SwingUtilities.convertPoint(panel, Point(0, 0), editorComponent)
|
||||
|
||||
val xCoordinate = panelLocationInEditor.x + xOffset
|
||||
val yCoordinate = panelLocationInEditor.y + yOffset
|
||||
return Rectangle(xCoordinate, yCoordinate, toolbar.width, toolbar.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package org.jetbrains.plugins.notebooks.ui.jupyterToolbar
|
||||
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import java.awt.event.ComponentEvent
|
||||
import java.awt.event.ComponentListener
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import javax.swing.JPanel
|
||||
|
||||
/**
|
||||
* Adds listeners for "above cell" panels to trigger toolbar-related functions in the [JupyterToolbarService].
|
||||
*/
|
||||
class JupyterToolbarPanelListeners( // PY-66455
|
||||
private val panel: JPanel,
|
||||
project: Project,
|
||||
private val editor: EditorImpl
|
||||
) : MouseAdapter(), ComponentListener {
|
||||
|
||||
private val toolbarService = JupyterToolbarService.getInstance(project)
|
||||
|
||||
init {
|
||||
panel.addMouseListener(this)
|
||||
panel.addComponentListener(this)
|
||||
}
|
||||
|
||||
override fun mouseEntered(e: MouseEvent?) {
|
||||
toolbarService.requestToolbarDisplay(panel, editor)
|
||||
}
|
||||
|
||||
override fun mouseExited(e: MouseEvent?) {
|
||||
toolbarService.requestToolbarHide()
|
||||
}
|
||||
|
||||
override fun mouseClicked(e: MouseEvent?) {
|
||||
toolbarService.hideToolbarUnconditionally()
|
||||
}
|
||||
|
||||
override fun componentResized(e: ComponentEvent?) {
|
||||
toolbarService.adjustToolbarPosition()
|
||||
}
|
||||
|
||||
override fun componentMoved(e: ComponentEvent?) {
|
||||
toolbarService.adjustToolbarPosition()
|
||||
}
|
||||
|
||||
override fun componentShown(e: ComponentEvent?) {
|
||||
toolbarService.hideToolbarUnconditionally()
|
||||
}
|
||||
override fun componentHidden(e: ComponentEvent?) {
|
||||
toolbarService.hideToolbarUnconditionally()
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package org.jetbrains.plugins.notebooks.ui.jupyterToolbar
|
||||
|
||||
import com.intellij.ide.ui.customization.CustomActionsSchema
|
||||
import com.intellij.openapi.actionSystem.ActionGroup
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.JBPopup
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.plugins.notebooks.ui.visualization.DefaultNotebookEditorAppearanceSizes
|
||||
import org.jetbrains.plugins.notebooks.ui.visualization.NotebookAboveCellDelimiterPanelNew
|
||||
import java.awt.MouseInfo
|
||||
import java.awt.Point
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.SwingUtilities
|
||||
import javax.swing.Timer
|
||||
|
||||
|
||||
/**
|
||||
* This class encapsulates a service that manages the display toggle action of a [JupyterToolbar] among multiple cells.
|
||||
*
|
||||
* The following rules apply:
|
||||
* - The toolbar is always positioned beneath the last cell (not managed by this service)
|
||||
* - Only one additional toolbar is allowed among cells (managed by this service)
|
||||
*
|
||||
* When a cursor hovers over a [NotebookAboveCellDelimiterPanelNew], a toolbar will appear.
|
||||
* If a toolbar is already displayed above another panel, this older instance will be hidden.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@Service(Service.Level.PROJECT)
|
||||
class JupyterToolbarService { // PY-66455
|
||||
private var currentPanel: JPanel? = null
|
||||
private var currentToolbar: JupyterToolbar? = null
|
||||
private var currentToolbarPopup: JBPopup? = null
|
||||
|
||||
private val hideToolbarTimer = Timer(TOOLBAR_HIDE_DELAY) { hideToolbarConditionally() }
|
||||
private val actionGroup: ActionGroup? = createActionGroup()
|
||||
|
||||
fun requestToolbarDisplay(panel: JPanel, editor: EditorImpl) {
|
||||
val shouldDisplayToolbar = currentPanel != panel || currentToolbarPopup == null || currentToolbarPopup?.isDisposed == true
|
||||
|
||||
if (shouldDisplayToolbar) {
|
||||
hideToolbarUnconditionally()
|
||||
currentPanel = panel
|
||||
createAndShowToolbar(panel, editor)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestToolbarHide() = hideToolbarTimer.restart()
|
||||
|
||||
private fun createAndShowToolbar(panel: JPanel, editor: EditorImpl) {
|
||||
actionGroup ?: return
|
||||
|
||||
if (currentToolbar == null) {
|
||||
currentToolbar = JupyterToolbar(actionGroup, editor.contentComponent)
|
||||
}
|
||||
|
||||
if (currentToolbarPopup == null) {
|
||||
currentToolbarPopup = JBPopupFactory.getInstance()
|
||||
.createComponentPopupBuilder(currentToolbar!!.component, panel)
|
||||
.setCancelOnClickOutside(true)
|
||||
.setCancelKeyEnabled(true)
|
||||
.setShowBorder(false)
|
||||
.setShowShadow(false)
|
||||
.createPopup().also {
|
||||
val point = calculatePopupLocation() ?: return
|
||||
it.show(RelativePoint(panel, point))
|
||||
}
|
||||
}
|
||||
hideToolbarTimer.stop()
|
||||
adjustToolbarPosition()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the mouse is over the toolbar before hiding it.
|
||||
* This is necessary because mouseExited events on the panel can trigger even when the mouse
|
||||
* is over the toolbar due to its position in the Z-stack.
|
||||
* If the mouse is indeed over the toolbar, hiding is deferred to prevent an unintended disappearance,
|
||||
* acting as an additional safeguard for better user experience.
|
||||
*/
|
||||
private fun hideToolbarConditionally() {
|
||||
if (currentToolbar == null || currentToolbarPopup == null || currentToolbarPopup!!.isDisposed) return
|
||||
|
||||
try {
|
||||
val mousePos = MouseInfo.getPointerInfo().location
|
||||
val content = currentToolbarPopup?.content
|
||||
if (content != null) {
|
||||
SwingUtilities.convertPointFromScreen(mousePos, content)
|
||||
|
||||
if (currentToolbar?.bounds?.contains(mousePos) == true) {
|
||||
hideToolbarTimer.restart()
|
||||
return
|
||||
} else {
|
||||
hideToolbarUnconditionally()
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalStateException) { hideToolbarUnconditionally() }
|
||||
}
|
||||
|
||||
fun hideToolbarUnconditionally() {
|
||||
currentToolbar = null
|
||||
currentPanel = null
|
||||
currentToolbarPopup?.let { p ->
|
||||
p.cancel()
|
||||
if (!p.isDisposed) { Disposer.dispose(p) }
|
||||
currentToolbarPopup = null
|
||||
}
|
||||
}
|
||||
|
||||
fun adjustToolbarPosition() {
|
||||
val toolbarPopup = currentToolbarPopup ?: return
|
||||
val panel = currentPanel ?: return
|
||||
// I had to use this method to correctly evaluate the toolbar's width
|
||||
currentToolbar?.updateActionsImmediately() ?: return
|
||||
|
||||
calculatePopupLocation()?.let {
|
||||
val relPoint = RelativePoint(panel, it)
|
||||
toolbarPopup.setLocation(relPoint.screenPoint)
|
||||
} ?: run {
|
||||
hideToolbarUnconditionally()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculatePopupLocation(): Point? {
|
||||
val panelHeight = currentPanel?.height ?: return null
|
||||
val panelWidth = currentPanel?.width ?: return null
|
||||
val toolbarHeight = currentToolbar?.height ?: return null
|
||||
val toolbarWidth = currentToolbar?.width ?: return null
|
||||
|
||||
val xOffset = (panelWidth - toolbarWidth) / 2
|
||||
val yOffset = (panelHeight - (1.5 * DELIMITER_SIZE) - (toolbarHeight / 2)).toInt()
|
||||
val result = Point(xOffset, yOffset)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createActionGroup(): ActionGroup? = CustomActionsSchema.getInstance().getCorrectedAction(ACTION_GROUP_ID) as? ActionGroup
|
||||
|
||||
companion object {
|
||||
private const val ACTION_GROUP_ID = "Jupyter.AboveCellPanelNew"
|
||||
private const val TOOLBAR_HIDE_DELAY = 600
|
||||
private val DELIMITER_SIZE = DefaultNotebookEditorAppearanceSizes.CELL_BORDER_HEIGHT / 2
|
||||
fun getInstance(project: Project): JupyterToolbarService = project.getService(JupyterToolbarService::class.java)
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package org.jetbrains.plugins.notebooks.ui.jupyterToolbar
|
||||
|
||||
object JupyterToolbarVisibilityManager {
|
||||
// simple singleton to keep only one active intercellular toolbar
|
||||
// not sure whether a more complex observer solution is actually needed
|
||||
private var currentActiveManager: JupyterToolbarManager? = null
|
||||
|
||||
fun requestToolbarDisplay(manager: JupyterToolbarManager) {
|
||||
if (currentActiveManager != manager) {
|
||||
currentActiveManager?.hideToolBar()
|
||||
currentActiveManager = manager
|
||||
}
|
||||
}
|
||||
|
||||
fun notifyToolbarHidden(manager: JupyterToolbarManager) {
|
||||
if (manager == currentActiveManager) {
|
||||
currentActiveManager = null
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-30
@@ -4,14 +4,16 @@ import com.intellij.ide.ui.customization.CustomActionsSchema
|
||||
import com.intellij.openapi.actionSystem.ActionGroup
|
||||
import com.intellij.openapi.editor.EditorKind
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.ui.scale.JBUIScale
|
||||
import org.jetbrains.plugins.notebooks.ui.jupyterToolbar.JupyterToolbar
|
||||
import org.jetbrains.plugins.notebooks.ui.jupyterToolbar.JupyterToolbarManager
|
||||
import java.awt.Dimension
|
||||
import java.awt.GridBagLayout
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.awt.event.ComponentAdapter
|
||||
import java.awt.event.ComponentEvent
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
class NotebookBelowLastCellPanelNew(val editor: EditorImpl) : JPanel(GridBagLayout()) {
|
||||
private var toolbar: JupyterToolbar? = null
|
||||
@@ -26,17 +28,9 @@ class NotebookBelowLastCellPanelNew(val editor: EditorImpl) : JPanel(GridBagLayo
|
||||
fun initialize() {
|
||||
// this toolbar is special - persistent and unique
|
||||
val actionGroup = createActionGroup() ?: return
|
||||
toolbar = JupyterToolbar(actionGroup).apply {
|
||||
targetComponent = editor.contentComponent
|
||||
}
|
||||
toolbar = JupyterToolbar(actionGroup, editor.contentComponent)
|
||||
add(toolbar)
|
||||
|
||||
toolbar?.let {
|
||||
it.bounds = calculateToolbarBounds()
|
||||
editor.contentComponent.revalidate()
|
||||
editor.contentComponent.repaint()
|
||||
}
|
||||
|
||||
adjustToolbarBounds()
|
||||
addComponentListeners()
|
||||
}
|
||||
|
||||
@@ -44,38 +38,38 @@ class NotebookBelowLastCellPanelNew(val editor: EditorImpl) : JPanel(GridBagLayo
|
||||
this.addComponentListener(object : ComponentAdapter() {
|
||||
override fun componentResized(e: ComponentEvent?) {
|
||||
super.componentResized(e)
|
||||
toolbar?.let {
|
||||
it.bounds = calculateToolbarBounds()
|
||||
revalidate()
|
||||
repaint()
|
||||
}
|
||||
adjustToolbarBounds()
|
||||
}
|
||||
|
||||
override fun componentShown(e: ComponentEvent?) {
|
||||
super.componentShown(e)
|
||||
toolbar?.let {
|
||||
it.bounds = calculateToolbarBounds()
|
||||
revalidate()
|
||||
repaint()
|
||||
}
|
||||
adjustToolbarBounds()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun calculateToolbarBounds(): Rectangle {
|
||||
val toolbarPreferredSize = toolbar?.preferredSize ?: Dimension(0, 0)
|
||||
val newBounds = JupyterToolbarManager.calculateToolbarBounds(editor,
|
||||
this,
|
||||
toolbarPreferredSize,
|
||||
extraYOffset = 30)
|
||||
return newBounds
|
||||
}
|
||||
|
||||
private fun createActionGroup(): ActionGroup? {
|
||||
return CustomActionsSchema.getInstance().getCorrectedAction(ACTION_GROUP_ID) as? ActionGroup
|
||||
}
|
||||
|
||||
private fun adjustToolbarBounds() {
|
||||
toolbar?.let { tb ->
|
||||
val toolbarPreferredSize = tb.preferredSize
|
||||
val xOffset = (this.width - toolbarPreferredSize.width) / 2
|
||||
val editorComponent = editor.contentComponent
|
||||
val panelLocationInEditor = SwingUtilities.convertPoint(this, Point(0, 0), editorComponent)
|
||||
|
||||
val xCoordinate = panelLocationInEditor.x + xOffset
|
||||
val yCoordinate = panelLocationInEditor.y + Y_OFFSET
|
||||
|
||||
tb.bounds = Rectangle(xCoordinate, yCoordinate, toolbarPreferredSize.width, toolbarPreferredSize.height)
|
||||
revalidate()
|
||||
repaint()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val Y_OFFSET = JBUIScale.scale(30)
|
||||
const val ACTION_GROUP_ID = "Jupyter.BelowCellNewPanel"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user